
This video is only available to subscribers. Start a subscription today to get access to this and 419 other videos.
Decoding Request Parameters
This episode is part of a series: Server-side Swift with Vapor.
1. Getting Started with Vapor 12 min |
2. Vapor Routing 14 min |
3. Leaf Templates 13 min |
4. Nesting Templates and Partials 8 min |
5. Vapor Demo: Tokenizr 21 min |
6. Setting up a Database with Fluent 19 min |
7. Creating, Updating, and Deleting Records with Fluent 19 min |
8. Vapor Futures 20 min |
9. Setting up Vapor with Postgresql 17 min |
10. UUID Primary Keys 13 min |
11. Timestamp Fields 4 min |
12. Refactoring to Protocols 12 min |
13. Parent Child Relationships and Foreign Keys 14 min |
14. Pivot Tables for Many to Many Relationships 14 min |
15. Vapor Controllers 15 min |
16. Decoding Request Parameters 9 min |
Specifying Request Content to Decode
We can leverage Vapor to automatically decode any Content
-conforming type. To start, we can decode our Project
model directly:
router.post(content: Project.self, use: create)
Our route handler also needs to change to add a new parameter:
private func create(_ req: Request, _ project: Project) throws -> Future<Project> {
return try project.save(on: req)
}
How easy is that! You can really see how strongly-typed nature of Swift can make certain jobs really easy in Vapor.
Preventing some attributes from being modified
We probably don't want people to modify the id
property, or any of the createdAt
, updatedAt
or any other internal field.
To specify this, we can create a simplified Codable
model that we'll use as the user-facing structure:
struct ProjectContent : Content {
var title: String?
var description: String?
func buildProject() -> Project {
return Project(title: String ?? "<untitled>", description: description ?? "")
}
}
Now we can modify the create route:
router.post(ProjectContent.self, use: create)
And the route function itself:
private func create(_ req: Request, _ projectContent: ProjectContent) throws -> Future<Project> {
return projectContent.buildProject().save(on: req)
}
With this in place, only the title
and description
are available for an API client to modify. This is also a great place to put fallback values.
Updating the Project
The process here is similar. First we update our route to define what the type of content will be expected on the request:
router.put(ProjectContent.self, at: Project.parameter, use: update)
Then modify the route function:
private func update(_ req: Request, _ projectContent: ProjectContent) throws -> Future<Project> {
return try req.parameters.next(Project.self)
.flatMap { project in
project.title = projectContent.title ?? project.title
project.description = projectContent.description ?? project.description
return project.update(on: req)
}
}
Here we make sure to only set the properties if they are non-nil, so that the project retains any previous values. Then we update the record in the database.