Using Fluent and Persisting Models in Vapor

The Fluent ORM lets you use any number of database engines in your Vapor app. Learn how to persist your models in your server side Swift apps using Vapor! By Tim Condon.

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

Running Migrations

Open configure.swift and, after app.databases.use(_:as:), add:

// 1
app.migrations.add(CreateAcronym())
  
// 2
app.logger.logLevel = .debug

// 3
try app.autoMigrate().wait()

Here your new code:

  1. Adds CreateAcronym to the list of migrations to run.
  2. Sets the log level for the app to debug. This provides more information and lets you see your migrations.
  3. Automatically runs migrations and waits for the result. Fluent lets you choose when to run your migrations. This is helpful when you need to schedule them. You can use wait() here since you’re not running on an EventLoop.

To test with PostgreSQL, you’ll run the Postgres server in a Docker container. Open Terminal and enter:

docker run --name postgres -e POSTGRES_DB=vapor_database \
  -e POSTGRES_USER=vapor_username \
  -e POSTGRES_PASSWORD=vapor_password \
  -p 5432:5432 -d postgres

Here’s what this does:

  1. Runs a new container named postgres.
  2. Then specifies the database name, username and password through environment variables.
  3. Lets apps connect to the Postgres server on its default port: 5432.
  4. Then runs the server in the background as a daemon.
  5. Uses the Docker image named postgres for this container. If the image isn’t present on your machine, Docker automatically downloads it.

To check if your database is running, enter the following in Terminal to list all active containers:

docker ps

Starting Docker Container

If you have any questions about Docker, check out this post. It breaks down everything you need to know.

Now you’re ready to run the app! Set the active scheme to TILApp with My Mac as the destination. Build and run. Check the console and see the migrations ran.

You’ll see something similar to this:

Acronym migration running

Now that you’ve run the migration, you need to save the model.

Saving Models

When your app’s user enters a new acronym, you need a way to save it.

In Vapor 4, Codable makes this trivial. Vapor provides Content, a wrapper around Codable, which lets you convert models and other data between various formats. It’s used extensively in Vapor.

Open Acronym.swift and add the following to the end of the file to make Acronym conform to Content:

extension Acronym: Content {}

Since Acronym already conforms to Codable via Model, you don’t have to add anything else. To create an acronym, the client sends a POST request containing a JSON payload that looks similar to this:

{
  "short": "OMG",
  "long": "Oh My God"
}

You need a route to handle this POST request and save the new acronym. Open routes.swift and at the end of routes(_:) add:

// 1
app.post("api", "acronyms") { req -> EventLoopFuture<Acronym> in
  // 2
  let acronym = try req.content.decode(Acronym.self)
  // 3
  return acronym.save(on: req.db).map { 
    // 4
    acronym 
  }
}

Here you:

  1. Register a new route at /api/acronyms that accepts a POST request and returns EventLoopFuture. It returns the acronym once it’s saved.
  2. Decode the request’s JSON into an Acronym model using Codable.
  3. Save the model using Fluent and the database from Request.
  4. Because save(on:) returns EventLoopFuture use map to return the acronym when the save completes.

Fluent and Vapor’s integrated use of Codable makes this simple. Since Acronym conforms to Content, it’s easily converted between JSON and Model. This lets Vapor return the model as JSON in the response without any effort on your part.

Build and run the app to try it out. A good tool to test this is RESTed, available as a free download from the Mac App Store. Other tools such as Paw and Postman are suitable as well.

In RESTed, configure the request as follows:

  • URL: http://localhost:8080/api/acronyms
  • method: POST
  • Parameter encoding: JSON-encoded

Add two parameters with names and values:

  • short: OMG
  • long: Oh My God

Setting the parameter encoding to JSON-encoded ensures RESTed sends the data as JSON. It’s important to note this also sets the Content-Type header to application/json, which tells Vapor the request contains JSON. If you’re using a different client to send the request, you may need to set this manually.

Click Send Request and you’ll see the acronym provided in the response. The id field has a value since you now saved it in the database:

RESTed response to POST

Troubleshooting

Some folks get the following error when they run the app:

“[ ERROR ] role "vapor_username" does not exist (InitializeSessionUserId)

You might have this issue if you have PostgreSQL installed on the machine hosting the docker container. To handle this error, stop the PostgreSQL server. For example, if you installed PostgreSQL using Homebrew, type the following into Terminal:

brew services stop postgresql

Then, you can start the docker container and run the app according to the instructions. That should solve the "vapor_username" does not exist’ issue. If it persists, join the chat and discuss the problem there.

Where to Go From Here?

You can download the final project by clicking the Download Materials button at the top and bottom of this page.

In this tutorial you learned how to create models in Vapor and save them to a database. If you enjoyed this tutorial, check out our full-length book on Vapor development: Server Side Swift with Vapor.

If you’re new to web development but have experience with Swift, you’ll find it’s easy to create robust, fully-featured web apps and web APIs with Vapor 4.

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

If you have any questions or comments please join the discussion below.