Vapor — Use controllers to organize your routes

Keep your code organized

Alexandre Cools
5 min readOct 27, 2020
Photo by Shawn Ang on Unsplash

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.

Create the controller Swift file

💡 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.

An empty UserController, ready to organize our code

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,

--

--

Alexandre Cools

iOS Developer @LunabeeStudio 👨🏻‍💻 — Sport addict 🏊‍♂️🚴‍♂️🏃‍♂️ — Travel enthusiast ✈️