Vapor — Use controllers to organize your routes
Keep your code organized
When your routes.swift
file become more and more larger, you would want to start organizing your code a bit, and that’s a great idea.
Why create controller?
When your code become larger and larger, it become difficult to maintain this code and to upgrade it. If you really want to put all your code in the same file, that’s up to you, nothing will stop you to do it, but that’s not a great idea, trust me.
The idea with Vapor is to separate all your routes in different controllers (that’s why there is a Controller
folder created when you generate a new Vapor project) to be able to maintain and upgrade easily your project.
💡 Tips: you can create as many as controller as you want.
One controller = one feature group
Basically, it’s a good idea to group all routes for the same feature. For example, if you have requests related to users, you should create a UsersController
, if you have requests related to activities, you should create a ActivitiesController
, and so on.
By doing this way, you know exactly what’s your routes feature. So, for example, if you have to update the function who update the user profile, you know the file you are looking for is UserController
.
Extract a route to a controller
As example, I’ll create a route who say hello to a user received as parameter of the route. So if I create it directly in the routes.swift
file, it should be like this:

That’s fine and that’s working well, but remember, we want to user controllers instead of write all of our code in this file.
Create the controller
A controller is nothing else than a Swift file. So, to get started, you only have to create a new Swift file and naming it like you want.

💡 Personally, my controllers name follow this rule: featureGroupName followed by Controller. For example, all user feature is grouped in the UserConroller file.
Once your file is created, by default, Xcode import Foundation
for us, but we don’t need it. Instead we’ll import Vapor
to have access to all functionality of the framework.
Then, we can create a new struct
(or class
if you prefer): our controller.

Now our controller created, we’ll create the function we’ll associated to our route.
Create the function who’ll be associated to the route
The function who represent a route is a basic function who take the request as parameter and return a response to the client. You can call it like you want, but I think it’s a good idea to name it with some logic. So if you get something with the route, you should probably start the function name with fetch or get for example. Or if the goal of your function is to update the username, you could start his name by update or post, etc.
💡 Personally, I like to start all my routes by their HTTP request method (GET
, POST
, etc).
So here’s the route to say hello to the user:

You’re right getWelcome
is not the sexiest function name, but by naming this way, I know directly that this route return a value to the client, in this case, a welcome value.
To be able to return error to clients (and so, use code like throw Abort(.badRequest)
), we have to mark it as throws
.

Move the route code to the new controller
Perfect, the function is now created, we can extract the route code in this function. To do that, we can open the routes.swift
file and our new UserController
, and then cut the following code (from the routes.swift
file):

and past it to the getWelcome(req: Request)
function (in the UserController.swift
file):

Link the route and the controller function
Now, the last thing we have to do is to inform our route that we want to use the getWelcome
function.
Start by opening the routes.swift
file. If you cut the code previously, you should have something like this:

(Right now, Xcode is pretty sad, but we’ll make him happy in a moment)
We don’t need the closure anymore, so we can remove it, and instead we’ll use the function we juste created before. Because this function is in our UserController
, we have to instantiate a new object to be able to use it.
If you remove the closure and instantiate a new UserController
object, you should have something like this:

(Xcode is not much happy, but that’s our next step)
And now, the last thing to do here is to link our function in the UserController
to our route. We can do it by adding use: userController.getWelcome
to our app.get
call.

That’s it, our route is linked to our getWelcome
function written in our UserController
and if you run your Vapor application, everything should be the same as before.

The only thing (and it’s a great thing) is that we have now organized our code to be more maintainable, congratulations! 🎉
(Note that we have done this for a GET
route, but you can do it for all HTTP request methods.)
🚀 What’s next
If you missed the previous articles about Vapor, you can find them here:
How to get started
Generated files overview
Create a GET route
Don’t forget to “clap” and share this article if you like it and want to see more content like this! 👏
If you have another way to organize your routes or if you have any question, I’ll be happy to read you in the comments section right bellow.
Thanks for reading,