When using Vapor to build a API, always use a method to fetch a object,
request.parameters.next(type.self)
It seems a method to extract the url parameter, why it return the result from the database ? Could not found any clues from the framework's source code. How can I find the answer ? Thanks.
This how Parameter
protocol looks like
public protocol Parameter {
associatedtype ResolvedParameter
static var routingSlug: String { get }
static func resolveParameter(_ parameter: String, on container: Container) throws -> ResolvedParameter
}
when you conform anything to Parameter
you should implement this function
static func resolveParameter(_ parameter: String, on container: Container) throws -> ResolvedParameter
which should parse string parameter from URL and return some object as a result. And as Parameter
is generic you can return any type you want.
Let's write an extension to conform Date
to Parameter
extension Date: Parameter {
public static func resolveParameter(_ parameter: String, on container: Container) throws -> Date {
guard let timeIntervalSince1970 = TimeInterval(parameter) else {
throw Abort(.notAcceptable, reason: "Unable to parse \"\(parameter)\" parameter")
}
return Date(timeIntervalSince1970: timeIntervalSince1970)
}
}
Parameter
's method parses String
parameter from URL and returnsDate
, but you also can return something else, e.g. TimeInterval
since Parameter
is generic protocol
extension Date: Parameter {
public static func resolveParameter(_ parameter: String, on container: Container) throws -> TimeInterval {
guard let timeIntervalSince1970 = TimeInterval(parameter) else {
throw Abort(.notAcceptable, reason: "Unable to parse \"\(parameter)\" parameter")
}
return timeIntervalSince1970
}
}
When you conform your Fluent model to Parameter
it already have an implementation for Parameter
protocol in its extensions, that's why you shouldn't declare resolveParameter
function manually.
Let's take a look how it works if you declare resolveParameter
method manually in e.g. User
model
extension User {
public static func resolveParameter(_ parameter: String, on container: Container) throws -> Future<User> {
// e.g. User's primary key is UUID
guard let id = UUID(parameter) else {
throw Abort(.notAcceptable, reason: "Unable to parse \"\(parameter)\" into UUID")
}
// getting database connection from pool
return container.requestPooledConnection(to: .psql).flatMap { conn in
// querying user by provided primary key
return User.query(on: conn)
.filter(\.id == id)
.first()
.unwrap(or: Abort(.notFound, reason: "Unable to find user by provided primary key"))
.always {
// will release connection in any case
try? container.releasePooledConnection(conn, to: .psql)
}
}
}
}
So as you can see you can implement resolveParameter
to return anything you want.