Getting Started with Server-Side Swift with Vapor 4

Get started quickly with Server-side Swift using Vapor and build your first Vapor web app! By Tim Condon.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Creating Your Own Routes

Note: This section uses Xcode. If you’re developing on Linux, use your favorite editor, then use swift run to build and run your app.

Now that you’ve made your first app, it’s time to see how easy it is to add new routes with Vapor. If the Vapor app is still running, stop it by pressing Control-C in Terminal. Next enter:

open Package.swift

This opens the project in Xcode as a SwiftPM workspace. It will take a couple of minutes for Xcode to download the dependencies. When it’s finished, open routes.swift in Sources/App. You’ll see the route you visited above. To create another route, add the following after the app.get("hello") closure:

app.get("hello", "vapor") { req -> String in
  return "Hello Vapor!"
}

Here’s what this does:

  • Add a new route to handle a GET request. Each parameter to app.get is a path component in the URL. This route is invoked when a user enters http://localhost:8080/hello/vapor as the URL.
  • Supply a closure to run when this route is invoked. The closure receives a Request object.
  • Return a string as the result for this route.

In the Xcode toolbar, select the HelloVapor scheme and choose My Mac as the device.

Xcode scheme

Build and run by clicking the Run button or pressing Command-R. You may be prompted by Xcode to enter your password on this first run, so go ahead and do so. Once you see the “Server starting on http://127.0.0.1:8080” message in the console, visit http://localhost:8080/hello/vapor in your browser.

Hello Vapor route

What if you want to say hello to anyone who visits your app? Adding every name in the world would be quite impractical! There must be a better way. There is, and Vapor makes it easy.

Add a new route that says hello to whomever visits. For example, if your name is Tim, you’ll visit the app using the URL http://localhost:8080/hello/Tim and it says “Hello, Tim!”. Add the following after the code you just entered:

// 1
app.get("hello", ":name") { req -> String in
  //2
  guard let name = req.parameters.get("name") else {
    throw Abort(.internalServerError)
  }
  // 3
  return "Hello, \(name)!"
}

Here’s the play-by-play:

  1. Use :name to designate a dynamic parameter.
  2. Extract the user’s name, which is passed in the Request object. If Vapor can’t find a parameter called name, throw an error.
  3. Use the name to return your greeting.

Build and run. In your browser, visit http://localhost:8080/hello/Tim. Try replacing Tim with some other values.

Hello Name!

Accepting Data

Most web apps must accept data. A common example is user login. To do this, a client sends a POST request with a JSON body, which the app must decode and process.

Vapor makes decoding data easy thanks to its strong integration with Swift’s Codable protocol. You give Vapor a Codable struct that matches your expected data, and Vapor does the rest. Create a POST request to see how this works.

Note: This tutorial uses the RESTed app, available as a free download from the Mac App Store. If you like, you may use another REST client to test your APIs.

Set up the request as follows:

  • URL: http://localhost:8080/info
  • Method: POST
  • Add a single parameter called name. Use your name as the value.
  • Select JSON-encoded as the request type. This ensures that the data is sent as JSON and that the Content-Type header is set to application/json. If you are using a different client you may need to set this manually.

Your request should look similar to the following:

RESTed POST request

Go back to Xcode, open routes.swift and add the following to the end of the file to create a struct called InfoData to represent this request:

struct InfoData: Content {
 let name: String
}

This struct conforms to Content which is Vapor’s wrapper around Codable. Vapor uses Content to extract the request data, whether it’s the default JSON-encoded or form URL-encoded. InfoData contains the single parameter name.

Next, add a new route after the app.get("hello", "vapor") closure:

// 1
app.post("info") { req -> String in
  // 2
  let data = try req.content.decode(InfoData.self)
  // 3
  return "Hello \(data.name)!"
}

Here’s what this does:

  1. Adds a new route handler to handle a POST request for the URL http://localhost:8080/info. This route handler returns a String.
  2. Decode the request’s body using InfoData.
  3. Returns the string by pulling the name out of the data variable.

Build and run the app. Send the request from RESTed and you’ll see the response come back:

RESTed results

Note: If you are into curl here’s the corresponding call:
curl http://localhost:8080/info \
  -H "Content-Type: application/json" \
  -d '{"name":"Tim"}'
curl http://localhost:8080/info \
  -H "Content-Type: application/json" \
  -d '{"name":"Tim"}'

This may seem like a lot of boilerplate to extract a single parameter from JSON. However, Codable scales up and allows you to decode complex, nested JSON objects with multiple types in a single line.

Returning JSON

Vapor also makes it easy to return JSON in your route handlers. This is a common need when your app provides an API service. For example, a Vapor app that processes requests from an iOS app needs to send JSON responses. Vapor again uses Content to encode the response as JSON.

Open routes.swift and add the following struct, called InfoResponse, to the end of the file:

struct InfoResponse: Content {
  let request: InfoData
}

This struct conforms to Content and contains a property for the request.

Next, replace the previous app.post("info") with the following:

// 1
app.post("info") { req -> InfoResponse in
  let data = try req.content.decode(InfoData.self)
  // 2
  return InfoResponse(request: data)
}

Here’s what changed:

  1. The route handler now returns the new InfoResponse type.
  2. A new InfoResponse is constructed using the decoded request data.

Build and run the app. Send the same request from RESTed. You’ll see a JSON response containing your original request data:

RESTed JSON response

Troubleshooting Vapor

In this and future Vapor apps, you may encounter errors in your projects. There are a number of steps to take to troubleshoot any issues. Here’s some tips:

  1. Update dependencies
  2. Clean and rebuild
  3. Ask the community for help :]