
This video is only available to subscribers. Start a subscription today to get access to this and 472 other videos.
Vapor Controllers
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 |
Episode Links
- Paw - a useful API bench tool for macOS.
Adding the Projects Controller
final class ProjectsController : RouteCollection {
func boot(router: Router) throws {
}
}
We can then use router
just like we were before to register routes that belong together. We'll use this controller to handle all routes related to retrieving and managing Projects.
Let's create the first route to list all projects:
private func index(_ req: Request) throws -> Future<[Project]> {
}
Before we can return the projects array like this, we have to conform it to the Content
protocol.
extension Project : Content { }
private func index(_ req: Request) throws -> Future<[Project]> {
return Project.query(on: req)
.order(\.createAt, .descending)
.all()
}
Since .all()
returns an EventLoopFuture<[Project]>
already, we're basically done.
Let's hook this up to the routing system.
First, in routes.swift
we have to register this route collection. We'll do this by nesting them all under a group called "projects"
. This means they'll all share a common prefix in the URL, so essentially our index route will be the root of this group.
try router.grouped("projects").register(collection: ProjectsController())
Then in the controller class:
final class ProjectsController : RouteCollection {
func boot(router: Router) throws {
router.get(use: index)
}
}
The Show Route
Showing a single project would require the UUID parameter in the URL. Since these map directly to the primary key of a fluent model, we can lean on the framework here to do all of the heavy lifting.
We'll start by defining the route function that will expect a primary key as the first (and only route component):
private func show(_ req: Request) throws -> Future<Project> {
return try req.parameters.next(Project.self)
}
Then we can wire it up:
router.get(Project.parameter, use: show)
The Create Route
For this demo we'll just hard code some values so we can skip taking input from the request for now. We'll tackle this in the next episode.
private func create(_ req: Request) throws -> Future<Project> {
let project = Project(title: "New Project", description: "New Description")
return project.save(on: req)
}
The Update and Delete Routes
For updating, we can do something similar, however we first need to load the project from the database, so we have to leverage flatMap
to stitch together the two futures.
private func update(_ req: Request) throws -> Future<Project> {
return try req.parameters.next(Project.self)
.flatMap { project in
project.title = project.title + " UPDATED"
return project.update(on: req)
}
}
Implementing delete is similar:
private func delete(_ req: Request) throws -> Future<HTTPStatus> {
return try req.parameters.next(Project.self)
.flatMap { project in
return project.delete(on: req).transform(to: .noContent)
}
}
And in the boot
function we can wire up these new routes:
// ...
router.post(use: create)
router.put(Project.parameter, use: update)
router.delete(Project.parameter, use: delete)