Tutorial: How to set up a Vapor 2 project

Martin Lasek
5 min readSep 18, 2017

By the end of this tutorial you will be able to set up a vapor project and implement a simple route returning a string /number / json :)

You can find the result of this tutorial on github here

1. Install Xcode

With Xcode you will automagically have swift installed. Go download Xcode from the App Store. And finish the installation by opening Xcode and following the instructions.

2. Check Vapor 2 compatibility

When you’re done installing, let us check that your system is ready now for Vapor 2 by executing the following in your terminal:

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

You should get:

✅ Compatible with Vapor 2

3. Install the Vapor toolbox

Before we create our first Vapor project let us install a super convenient command-line interface (cli) that will help us a lot in the future. The one and only Vapor toolbox.

We will install Vapor toolbox via Homebrew. If you don’t have it yet I highly recommend to get it. It makes it super easy for you to install dependencies you definitely will need later when creating larger projects with Vapor. For installation execute the following in your terminal:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Now add Homebrew Tap and we can finally install Vapor toolbox 😊

brew tap vapor/homebrew-tap
brew update
brew install vapor

4. Create your first Vapor project

Now having Vapor toolbox, creating a new project is as simple as typing:

vapor new yourProjectName --branch=vapor-2

This will create a new project based on the api-template you can find in the repository of Vapor on Github here. Next step — generating an Xcode project, from within your project yourProjectName/ execute the following:

vapor xcode -y

This may take a while.. but it will generate the Xcode project and open it for you (thanks vapor toolbox 🤜🏻 🤛🏻).

5. Clean up unnecessary files + code

You should have a project structure like this now:

yourProjectName/
├── Package.swift
├── Sources/
│ ├── App/
│ │ ├── Controllers/
│ │ │ └── PostController.swift
│ │ ├── Models/
│ │ │ └── Post.swift
│ │ ├── Routes/
│ │ │ └── Routes.swift
│ │ └── Setup/
│ │ ├── Config+Setup.swift
│ │ └── Droplet+Setup.swift
│ └── Run/
├── Tests/
├── Config/
├── Public/
├── Dependencies/
└── Products/

I like to delete (move to trash) everything that is unimportant for now or we are about to implement by our own. That way I want to ensure we know what we do, need and use and gain a better understanding 😊.

yourProjectName/
├── Package.swift
├── Sources/
│ ├── App/
│ │ ├── Controllers/
│ │ │ └── PostController.swift // delete
│ │ ├── Models/
│ │ │ └── Post.swift // delete
│ │ ├── Routes/
│ │ │ └── Routes.swift
│ │ └── Setup/
│ │ ├── Config+Setup.swift
│ │ └── Droplet+Setup.swift
│ └── Run/
├── Tests/
├── Config/
├── Public/
├── Dependencies/
└── Products/

Note: If you want to learn more about Controllers and Models - I wrote tutorials on them too: Controllers and Models 😊

Next: delete from within Setup/Config+Setup.swift following lines:

import FluentProvider  // deleteextension Config {
public func setup() throws {
Node.fuzzy = [Row.self, JSON.self, Node.self] // delete

try setupProviders()
try setupPreparations()
}
private func setupProviders() throws {
try addProvider(FluentProvider.Provider.self) // delete
}
private func setupPreparations() throws {
preparations.append(Post.self) // delete
}
}

From Config/droplet.json delete the “prepare” string:

..."commands": [
"prepare" // delete
]
...

Within the Package.swift delete the FluentProvider:

// swift-tools-version:4.0import PackageDescriptionlet package = Package(
name: "my-first-route",
products: [
.library(name: "App", targets: ["App"]),
.executable(name: "Run", targets: ["Run"])
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "2.1.0")), // don't forget to delete that comma 😉
.package(url: "https://github.com/vapor/fluent-provider.git", .upToNextMajor(from: "1.2.0")), // delete
],
targets: [
.target(name: "App", dependencies: ["Vapor", "FluentProvider"],
exclude: [
"Config",
"Public",
"Resources",
]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: ["App", "Testing"])
]
)

And everything from Routes/Routes.swift like so:

extension Droplet {
func setupRoutes() throws {
... // delete everything within this function body
}
}

For our changes or deletions to be applied we need to execute in our terminal:

vapor update -y

6. Implement your first route!

There are several HTTP Methods from which GET, POST, PUT and PATCH are probably the most known ones. We want to GET data for example a String. Maybe your name? Or GET a number. Maybe your age?

Let us implement our first GET route by inserting into Routes/Routes.swift:

extension Droplet {
func setupRoutes() throws {
get("name") { req in
return "Ethan Hunt"
}

}
}

By using the function get(“name”) we would define, that this route is reachable if it is requested via GET at the url /name.

If you now hit cmd + r or the play button on top of Xcode, it will start the application under localhost with the port 8080. With the given route you can get the name in your browser now under: 127.0.0.1:8080/name.

Note: make sure to select Run as a scheme next to your button before running the app

Note: The port from where you can reach your app is defined within Config/server.swift — you can change it as you like and re-run the app :)

You can add more routes and try more out, like returning a number or json:

extension Droplet {
func setupRoutes() throws {
get("name") { req in
return "Ethan Hunt"
}
get("age") { req in
return "\(23)"
}
get("json") { req in
return try JSON(node: ["name": "Martin J. Lasek", "age": 26])
}

}
}

Don’t forget to run or cmd + r in Xcode after every change in the code in order to recompile it and be able to see the results in your browser 🤓

That’s it! You successfully implemented your first Vapor project 🎉 !!

Thank you a lot for reading! If you have any suggestions or improvements let me know! I would love to hear from you! 😊

--

--

Martin Lasek

I'm an always optimistic, open minded and knowledge seeking fullstack developer passionate about UI/UX and changing things for the better :)