35

Using Fluent and Persisting Models in Vapor [FREE]

 5 years ago
source link: https://www.tuicool.com/articles/hit/FJ3qUzB
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Fluent is Vapor’s ORM or object relational mapping tool. It’s an abstraction layer between the Vapor application and the database, and it’s designed to make working with databases easier. Using an ORM such as Fluent has a number of benefits.

The biggest benefit is you don’t have to use the database directly! When you interact directly with a database, you write database queries as strings. These aren’t type-safe and can be painful to use from Swift.

Fluent benefits you by allowing you to use any of a number of database engines, even in the same app. Finally, you don’t need to know how to write queries since you can interact with your models in a “Swifty” way.

Models are the Swift representation of your data and are used throughout Fluent. Models are the objects, such as user profiles, you save and access in your database. Fluent returns and uses type-safe models when interacting with the database, giving you compile-time safety.

In this tutorial, you’ll learn how to use Fluent to save data in Vapor applications.

Note : This tutorial follows on from the setup in the “Getting Started with Server-side Swift using Vapor” tutorial . If you haven’t followed those steps, please visit that tutorial now and return here when you’re done.

Getting Started

Start by creating a new project, using the Vapor Toolbox. In Terminal, enter the following commands:

cd ~/vapor
vapor new TILApp

The first command takes you into a directory called vapor inside your home directory and assumes that you completed the steps in the “Getting Started with Server-side Swift using Vapor” tutorial.

The second command creates a new Vapor 3 project called TILApp using the default template.

vapor-new-til-650x463.png

The template provides examples files for models and controllers. You’ll build your own so delete the examples. In Terminal, enter:

cd TILApp
rm -rf Sources/App/Models/*
rm -rf Sources/App/Controllers/*

Since Xcode projects are discardable when using Vapor — they’re entirely optional — it’s best practice to create your project files outside of Xcode. This lets Swift Package Manager , which is used by Vapor Toolbox, ensure that they link to the correct targets. Create a file to hold the Acronym model:

touch Sources/App/Models/Acronym.swift

This command creates a Swift file inside the App module’s Models directory called Acronym.swift . Now generate your Xcode project:

vapor xcode -y

This will open the project in Xcode.

Open configure.swift in the App folder, find the Configure migrations group and delete the following line:

migrations.add(model: Todo.self, database: .sqlite)

Next, open routes.swift and delete the following lines:

// Example of configuring a controller
let todoController = TodoController()
router.get("todos", use: todoController.index)
router.post("todos", use: todoController.create)
router.delete("todos", Todo.parameter, use: todoController.delete)

This removes the remaining references to the template’s example model and controller.

Creating the Model

Open Acronym.swift and add the following to create the basic model for the acronym:

import Vapor
import FluentSQLite

final class Acronym: Codable {
  var id: Int?
  var short: String
  var long: String

  init(short: String, long: String) {
    self.short = short
    self.long = long
  }
}

The model contains two String properties to hold the acronym and its definition. It also contains an optional id property that stores the ID of the model, if one has been set.

All Fluent models must conform to Codable . It’s also good practice to mark classes final , where possible, as it provides a performance benefit. The ID is set by the database when the acronym is saved.

Next make Acronym conform to Fluent’s Model . Add the following at the end of the file:

extension Acronym: Model {
  // 1
  typealias Database = SQLiteDatabase
  // 2
  typealias ID = Int
  // 3
  public static var idKey: IDKey = \Acronym.id
}

Here’s what this does:

  1. Tells Fluent what database to use for this model. The template is already configured to use SQLite.
  2. Tells Fluent what type the ID is.
  3. Tells Fluent the key path of the model’s ID property.

But this code can be improved further with SQLiteModel . Replace:

extension Acronym: Model {
  typealias Database = SQLiteDatabase
  typealias ID = Int
  public static var idKey: IDKey = \Acronym.id
}

with the following:

extension Acronym: SQLiteModel {}

The Fluent packages provide Model helper protocols for each database provider so you don’t have to specify the database or ID types, or the key. The SQLiteModel protocol must have an ID of type Int? called id , but there are SQLiteUUIDModel and SQLiteStringModel protocols for models with IDs of type UUID or String . If you want to customize the ID property name, you must conform to the standard Model protocol.

Creating a Table for the Model

To save the model in the database, you must create a table for it. Fluent does this with a migration . Migrations allow you to make reliable, testable, reproducible changes to your database. They are commonly used to create a database schema , or table description, for your models. They are also used to seed data into your database or make changes to your models after they’ve been saved.

Add the following at the end of Acronym.swift to make the model conform to Migration :

extension Acronym: Migration {}

That is all you need to do! Fluent infers the schema for your model thanks to Codable . For basic models you can use the default implementations for Migration . If you need to change your model later or do more complex things, such as marking a property as unique, you may need to implement your own migrations.

Now that Acronym conforms to Migration , you can tell Fluent to create the table when the application starts. Open configure.swift and find the section labeled // Configure migrations . Add the following before services.register(migrations) :

migrations.add(model: Acronym.self, database: .sqlite)

Fluent supports mixing multiple databases in a single application, so you specify which database holds each model. Migrations only run once ; once they have run in a database, they are never executed again. It’s important to remember this as Fluent won’t attempt to recreate a table if you change the model.

Set the active scheme to Run with My Mac as the destination. Build and run. Check the console and see that the migrations have run. You should see something similar to the console output below:

acronyn-migration-complete-650x395.png

Saving Models

When your app’s user enters a new acronym, you need a way to save it. In Swift 4 and Vapor 3, Codable makes this trivial. Vapor provides Content , a wrapper around Codable , which allows you to convert models and other data between various formats. This is 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 , you don’t have to add anything else. To create an acronym, the user’s browser sends a POST request containing a JSON payload that looks similar to the following:

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

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

// 1
router.post("api", "acronyms") { req -> Future<Acronym> in
  // 2
  return try req.content.decode(Acronym.self).flatMap(to: Acronym.self) { acronym in
    // 3
    return acronym.save(on: req)
  }
}

Here’s what you do here:

  1. Register a new route at /api/acronyms that accepts a POST request and returns Future . It returns the acronym once it’s saved.
  1. Decode the request’s JSON into an Acronym model using Codable . This returns a Future so it uses a flatMap(to:) to extract the acronym when the decoding completes. In this route handler, you’re calling decode(_:) on Request yourself. You’re then unwrapping the result as decode(_:) returns a Future .
  2. Save the model using Fluent. This returns Future as it returns the model once it’s saved.

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 allows Vapor to return the model as JSON in the response without any effort on your part.

Build and run the application 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 the data is sent 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 will have a value as it has now been saved in the database:

create-acronym-650x462.png

Where to Go From Here?

You can download the final project for this tutorial with the Download Materials button found at the top and bottom of this page.

This tutorial has introduced you to Fluent, and how to create models in Vapor and save them to a database. 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!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK