Routing in Vapor 2.0, Part 1: Basic Routing

917 Views

Hello droplets! Routing is one of the core functions of any backend framework. It is quite simple and elegant with vapor. So let's begin!

Create a new Vapor project, called Routing, by running:

    $ vapor new Routing --template=api

Then run vapor xcode to create the Xcode project, and press y when prompted to open the Xcode project.

First, delete the Post.swift file and the PostController.swift file, we will not be using them. Then, in the setupPreparations() method, in Config+Setup.swift, delete the line preparations.append(Post.self).

This entire tutorial will take place in Routes.swift. Delete all of the content from the setupRoutes() function.

Basic route

First, let's make a simple GET request. add the following route to setupRoutes():

    get("hello") { request in
        return "Hello, Vaporists!"
    }

The get function is called on our instance of droplet. All routes in vapor are called from the instance of our droplet.

Every route in vapor has 3 things:

  • A method (get, post, put, patch, delete)
  • A path, supplied by the user ( `"hello"` in our case)
  • a closure with the request

Also, we may notice that we returned a string. Every route closure in Vapor can return 1 of 3 ways:

  • a Response
  • a type conforming to the ResponseRepresentable protocol
  • throw an error that conforms to Vapor.error

Nesting Routes

Nesting a hard-coded route is quite simple in vapor. Add the following to setupRoutes():

    get("hi/how/are/you") { request in
        return "this path is /hi/how/are/you"
    }

Custom Response:

We can also return a custom Response object as well. First, add import HTTP to the top of your Routes.swift file. Now, for example, we can redirect:

    get("foo") { request in
        return Response(redirect: "https://apple.com")
    }

Navigating to /foo will now redirect you to the Apple website.

or we can return a certain status:

    get("bar") { request in
        return Response(status: Status.forbidden)
    }

Like Status.forbidden, we can also return other instances of the Status enum. Some of the more common ones are:

    Status.accepted
      Status.authenticationTimeout
      Status.badRequest
      Status.badGateway
      Status.created
      Status.notFound

Or, we can return a Response with a status and customized JSON:

    get("vapor") { request in
        return try Response(status: Status.accepted, json: JSON(node: ["yourStatus here": "hello world!"]))
    }
    

Parameters

Oftentimes we need routes such as /posts/1, for showing a post with an id of 1, or /posts/1/comments to show the post's comments. Vapor handles this very elegantly with its type-safe Parameterizable protocol:

    get("post", Int.parameter) { request in
        let parameter = try request.parameters.next(Int.self)
        return "You requested route /post/\(parameter)"
    }
        
    get("post", Int.parameter, "comments") { request in
        let parameter = try request.parameters.next(Int.self)
        return "You requested route /post/\(parameter)/comments"
    }

With the Parameterizable protocol, any type that conforms to it can be represented as a parameter as above. If your uniqueId is not an int, but a string, that is also Parameterizable:

    get("heart", String.parameter) { request in
        let parameter = try request.parameters.next(String.self)
        return "You requested route /heart/\(parameter)"
    }

Part 2 of this series on Routing in vapor will go more in depth on the Parameterizable protocol, and how we can use it with our models to efficiently retrieve objects.

Fallback Routes

A fallback route is defined in vapor as follows:

    get("foobarbaz", "*") { request in
        // this route matches:
           // /foobarbaz/1
           // /foobarbaz/1/2/3
        return "this is a fallback route"
    }

As the second parameter, simply put a "*", and the route will match anything, as long as it begins with foobarbaz

Groups

If we need to put multiple routes underneath one common route, for example /v1/users and /v1/posts and /v1/comments, we can easily group them:

    group("v1") { v1 in
        v1.get("users") { request in
            return "this route is /v1/users"
        }
        v1.get("comments") { request in
            return "this route is /v1/comments"
        }
    }

Alternatively, you can do the exact same as above, using this syntax:

    let v1 = grouped("v1")
    v1.get("users") { request in
        return "this route is /users/all"
    }
    v1.get("comments") { request in
        return "this route is /users/none"
    }

And of course, you can combine different types of routes as well, such as grouping and parameters:

    v1.get("users", Int.parameter) { request in
        let parameter = try request.parameters.next(Int.self)
        return "You requested /v1/users/\(parameter)"
    }

That's it for this beginning tutorial to routing in Vapor 2! Check back soon for Part 2 of the series, which will focus on using the Parameterizable protocol with your models, organizing your routes in controllers, and route collections. Thanks for reading!



Enjoy this article? Consider supporting VaporForums by following us on Twitter! Get the latest Vapor articles, tutorials, and news.