Posted 8/1/2018.
In Part 3 we started working with a Park
model and defined two endpoints that returned information about parks. We used an in-memory array to hold Park
instances. In this tutorial we'll set up a PostgreSQL database to work with Vapor so we can start persisting model objects between sessions and define the basic CRUD endpoints for Park
.
We'll use Homebrew, a popular package manager for macOS, to install postgres. To install Homebrew, open a new Terminal window and enter the following:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Next we'll install brew services
. In order to work with PostgreSQL locally, we'll need to start a PostgreSQL server, and brew services makes it easier to start and stop the server.
brew tap homebrew/services
Now let's use Homebrew to install Postgres:
brew install postgresql
To start a PostgreSQL server, run:
brew services start postgresql
Now run brew services list
. You should see that the status of postgresql
is "started".
To create our NationalParks database, run createdb NationalParks
. To work with the database locally, run psql NationalParks
.
At this point, the database is empty, but we can run a few commands to get basic information about it. Try each of the following:
SELECT current_database();
SELECT version();
\dt
The first should return the name of the database, NationalParks
. The second should return the Postgres version and information about your macOS setup. The third lists relations in the database. Currently it should say "No relations found."
Run \q
to quit psql.
We're now ready to add Postgres to our Vapor project. Replace Package.swift
with the following:
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "NationalParks",
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
.package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0")
],
targets: [
.target(name: "App", dependencies: ["Vapor", "FluentPostgreSQL"]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: ["App"])
]
)
Back in Terminal, run vapor update -y
. Your Xcode project should automatically open when the update is finished.
Next we need to configure our Vapor project to use Postgres. Replace configure.swift
with the following:
import Vapor
import FluentPostgreSQL
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
let router = EngineRouter.default()
try routes(router)
services.register(router, as: Router.self)
try services.register(FluentPostgreSQLProvider())
let psqlConfiguration = PostgreSQLDatabaseConfig(
hostname: "127.0.0.1",
port: 5432,
username: "[MAC_USERNAME]",
database: "NationalParks",
password: nil
)
services.register(psqlConfiguration)
var middlewares = MiddlewareConfig()
middlewares.use(ErrorMiddleware.self)
services.register(middlewares)
}
Make sure to replace the value for username
with your own Mac username.
Now let's see if our setup is working. To do that we'll run the same SELECT version();
query we ran earlier in psql in a Vapor route. Replace routes.swift
with the following:
import Vapor
import FluentPostgreSQL
public func routes(_ router: Router) throws {
router.get("version", use: databaseVersion)
}
private func databaseVersion(_ request: Request) throws -> Future<String> {
return request.withPooledConnection(to: .psql) { (connection: PostgreSQLDatabase.Connection) in
return connection.query("SELECT version();").map(to: String.self) { rows in
return try rows[0].firstValue(name: "version")?.decode(String.self) ?? ""
}
}
}
In Vapor 3, requests have convenience methods to get a database connection. We use that here to establish a connection to our Postgres database, then execute our version query and map the result to a String. If you run this and go to /version
in your browser, you should see the same output you saw earlier in psql.
In this part, we installed PostgreSQL, created a database, and configured Vapor to use it. Next we'll add a table for our Park
model and define a basic controller.