Skip to content

Routing Parameters

Traditional web frameworks leave room for error in routing by using strings for route parameter names and types. Vapor takes advantage of Swift's closures to provide a safer and more intuitive method for accessing route parameters.

Seealso

Route parameters refer to segments of the URL path (e.g., /users/:id). For query parameters (e.g., ?foo=bar) see request query parameters.

Type Safe

To create a type safe route simply replace one of the parts of your path with a Type.

drop.get("users", Int.parameter) { req in
    let userId = try req.parameters.next(Int.self)
    return "You requested User #\(userId)"
}

This creates a route that matches users/:id where the :id is an Int. Here's what it would look like using manual route parameters.

drop.get("users", ":id") { request in
    guard let userId = request.parameters["id"]?.int else {
        throw Abort.badRequest
    }

    return "You requested User #\(userId)"
}

Here you can see that type safe routing saves ~3 lines of code and also prevents runtime errors like misspelling :id.

Parameterizable

Any type conforming to Parameterizable can be used as a parameter. By default, all Vapor Models conform.

Using this, our previous example with users can be further simplified.

drop.get("users", User.parameter) { req in
    let user = try req.parameters.next(User.self)

    return "You requested \(user.name)"
}

Here the identifier supplied is automatically used to lookup a user. For example, if /users/5 is requested, the User model will be asked for a user with identifier 5. If one is found, the request succeeds and the closure is called. If not, a not found error is thrown.

Here is what this would look like if we looked the model up manually.

drop.get("users", Int.parameter) { req in
    let userId = try req.parameters.next(Int.self)
    guard let user = try User.find(userId) else {
        throw Abort.notFound
    }

    return "You requested \(user.name)"
}

Protocol

You can conform your own types to Parameterizable.

import Routing

extension Foo: Parameterizable {
    /// This unique slug is used to identify
    /// the parameter in the router
    static var uniqueSlug: String {
        return "foo"
    }


    static func make(for parameter: String) throws -> Foo {
        /// custom lookup logic here
        /// the parameter string contains the information
        /// parsed from the URL.
        ...
    }
}

Now you can use this type for type safe routing.

drop.get("users", "nickname", Foo.parameter) { req in
    let foo = try req.parameters.next(Foo.self)
    ...
}

Groups

Type-safe parameters also work with groups.

let userGroup = drop.grouped("users", User.parameter)
userGroup.get("messages") { req in
    let user = try req.parameters.next(User.self)

    ...
}