Getting Started with Server-Side Swift with Vapor

Get started quickly with Server-side Swift using Vapor and build your first Vapor web app in Swift!

4.8/5 5 Ratings · Leave a Rating

Version

  • Swift 4.2, macOS 10.14, Xcode 10

The dream of using the same language on the server that you use in your iOS apps is calling out to you! But maybe you’ve never done server-side work before?

Beginning a project in a new domain and using a new technology can be daunting, but Vapor makes it easy to get started with server-side Swift. Vapor even provides handy scripts to make sure your computer is configured correctly.

In this tutorial, you’ll start by installing the Vapor Toolbox, then use it to build and run your first project. You’ll finish by learning about routing, accepting data and returning JSON.

Getting Started

The first step in beginning Vapor development is to install the Vapor Toolbox.

The Vapor Toolbox is a command line interface (CLI) tool you use when developing Vapor apps. It provides several features, including:

  • Creating new apps from templates.
  • Building and running projects using the Swift toolchain.
  • Generating Xcode projects.
  • Deploying projects with Vapor Cloud.

Before you can install the toolbox, you need to ensure your system is compatible. To do this, you run the Vapor Check script, which verifies you have the necessary version of Swift installed.

Open Terminal, and execute the following command:

eval "$(curl -sL check.vapor.sh)"

This command also works on Linux.

Check Vapor command

If you receive errors when running this script, you’ll need to install Swift. On macOS, simply install Xcode from the Mac App Store. On Linux, use APT to install it as described below.

Vapor 3 requires Swift 4.1 or 4.2, both in Xcode and from the command line.

Installing on macOS

Vapor uses Homebrew to install the Toolbox.

If you don’t have Homebrew 2 installed, visit https://brew.sh and run the installation command.

In Terminal run the following commands:

brew tap vapor/tap
brew install vapor/tap/vapor

Installing on Linux

Everything you build with Vapor will work on any version of Linux that Swift supports. At the time of writing, these are Ubuntu 14.04, Ubuntu 16.04 and Ubuntu 18.04. The Vapor Toolbox works in exactly the same way, with the exception that you can’t use Xcode projects on Linux.

You install Vapor on Linux using the Vapor APT repository. Vapor maintains an open source APT repo at https://github.com/vapor/apt, which serves the same purpose as Vapor’s Brew tap. It allows for easy installation of packages and manages all the dependencies for you. When you install Vapor, it also installs Swift for you.

This tutorial uses Ubuntu 16.04 throughout when referring to Linux, but the other supported versions of Ubuntu should work in exactly the same way.

To use the Vapor APT repo, add it to your repository list. Enter the following at a shell prompt:

eval "$(curl -sL https://apt.vapor.sh)"
Note: You may need to install curl first before you can run this command if you are starting with a fresh Ubuntu image. Run sudo apt-get install curl -y to do so.

Once this completes, you can install the Toolbox (and Swift):

sudo apt-get install vapor -y

When this completes, you should be able to run the check script from above and get a successful result:

Check Vapor on Linux

Building Your First App

Setting up a Vapor project can seem complicated at first as there are a number of required files and directories. To help with this, the Toolbox can create a new project from a template. The default template is a simple API template, but it also has templates for web sites and authentication. You can even create your own templates.

First, create a new directory in your home directory or somewhere sensible to work on your Vapor projects. For example, enter the following commands in Terminal:

mkdir ~/vapor
cd ~/vapor

This creates a new directory in your home folder called vapor and navigates you there. Next, create your project with:

vapor new HelloVapor

You should see the following:

New Vapor Project

To build and start your app, run:

# 1
cd HelloVapor
# 2
vapor build
# 3
vapor run

Here’s what this does:

  1. cd is the “Change Directory” command and takes you into the project directory.
  2. This builds the app. It can take some time the first time since it must fetch all the dependencies.
  3. This runs the app. If the macOS Application Firewall pops up asking you to allow network connections, click Allow.

First build and run

The template has a predefined route, so open your browser and visit http://localhost:8080/hello and see the response!

Hello route

You can press Control-C in Terminal to stop the running app.

Swift Package Manager

Vapor Toolbox uses Swift Package Manager, or SPM, — a dependency management system similar to Cocoapods on iOS — to configure and build Vapor apps. Open your project directory and look at the structure. On macOS in Terminal, enter:

open .

Project structure

Notice there’s no Xcode project in your template even though you’ve built and run the app. This is deliberate. In fact, the project file is explicitly excluded from source control using the .gitignore file. When using SPM, Xcode projects are discardable and regenerated whenever you make project changes.

An SPM project is defined in the Package.swift manifest file. It declares targets, dependencies and how they link together. The project layout is also different from a traditional Xcode project. There is a Tests directory for tests. There is a Sources directory for source files. Each module defined in your manifest has its own directory inside Sources. Your sample app has an App module and a Run module, so Sources contains an App directory and a Run directory.

Inside the Run directory, there’s a single main.swift file. This is the entry point required by all Swift apps.

On iOS this is usually synthesized with a @UIApplicationMain attribute on the AppDelegate.

The template contains everything you need to set up your app and you shouldn’t need to change main.swift or the Run module. Your code lives in App or any other modules you define.

Creating Your Own Routes

This section uses Xcode. If you’re developing on Linux, use your favorite editor, then use the commands vapor build and vapor 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:

vapor xcode -y

This generates an Xcode project and opens it. Open routes.swift in Sources/App. You’ll see the route you visited above. To create another route, add the following after the router.get("hello") closure:

router.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 router.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 Run 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://localhost:8080” message in the console, visit http://localhost:8080/hello/vapor in your browser.

Hello Vapor route

Important note: In Xcode 10 and Swift 4.2 you may see two warnings. The first is a project warning saying the project can be converted to Swift 4.2. The second is a deprecation warning in the NIOOpenSSL package. You can safely ignore these.

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
router.get("hello", String.parameter) { req -> String in
  //2
  let name = try req.parameters.next(String.self)
  // 3
  return "Hello, \(name)!"
}

Here’s the play-by-play:

  1. Use String.parameter to specify that the second parameter can be any String.
  2. Extract the user’s name, which is passed in the Request object.
  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 3 makes decoding data easy thanks to its strong integration with Swift 4’s Codable. 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.

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 router.get("hello", "vapor") closure:

router.post(InfoData.self, at: "info") { req, data -> String in
  return "Hello \(data.name)!"
}

Here’s what this does:

  • Adds a new route handler to handle a POST request for the URL http://localhost:8080/info. This route handler returns a String. The route handler accepts a Content type as the first parameter and any path parameters after the at: parameter name. The route handler decodes the data and passes it to the closure as the second parameter.
  • 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

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 to return the incoming request:

struct InfoResponse: Content {
  let request: InfoData
}

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

Next, replace router.post(InfoData.self, at: "info") with the following:

// 1
router.post(InfoData.self, at: "info") { req, data -> InfoResponse in
    // 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.

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.

Regenerate Your Project

First and foremost, you should regenerate your Xcode project. In Terminal, type:

vapor xcode -y

This regenerates your project like the first time you created the Xcode project. This can fix issues such as missing files or project configuration errors.

Update your Dependencies

Another scenario you may encounter is hitting a bug in Vapor or another dependency you use. Make sure you are on the latest package version of any dependencies to see if the update fixes the issue. In Terminal, type:

vapor update

This uses the underlying swift package update command to pull down any updates to your dependencies and use the latest releases you support in Package.swift. Note that while packages are in the beta or release candidate stages, there may be breaking changes between updates.

Clean and Rebuild

Finally, if you are still having issues, you can use the software equivalent of “turn it off and on again”. In Xcode, use Command-Option-Shift-K to clean the build folder. You may also need to remove the build products created by the Vapor Toolbox. To do this, enter the following in Terminal:

rm -rf .build

This removes all build artifacts and your dependencies. You may also need to clear your derived data for the Xcode project as well. The “nuclear” option involves:

  • Remove the .build directory to remove any build artifacts.
  • Remove your .xcodeproj to delete the Xcode project and any misconfigurations.
  • Remove Package.resolved to ensure you get the latest dependencies next time you build.
  • Remove derived data to clear extra Xcode build artifacts.

Vapor Discord

The above steps usually fix most issues you might encounter that aren’t caused by your code. If all else fails, head to Vapor’s Discord server. There are thousands of developers discussing Vapor, its changes and helping people with issues.

Click the Join Chat button on Vapor’s web site: https://vapor.codes.

Where to Go From Here?

You can download the completed project for this tutorial using the “Download Materials” button at the top or bottom of this page.

This tutorial provided an overview of how to get started with Vapor and how to create basic routes. If you enjoyed this tutorial, why not check out our full-length book on Vapor development: Server Side Swift with Vapor?

If you’re a beginner to web development, but have worked with Swift for some time, you’ll find it’s easy to create robust, fully-featured web apps and web APIs with Vapor 3.

Whether you’re looking to create a backend for your iOS app, or want to create fully-featured web apps, Vapor is the perfect platform for you.

Questions or comments on this tutorial? Leave them in the comments below!

Average Rating

4.8/5

Add a rating for this content

5 ratings

Contributors

Comments