Currently in Beta - View old docs

Swift Kuery ORM

Swift Kuery ORM is an ORM (Object Relational Mapping) library for Swift built on top of Swift Kuery . Using it allows you to simplify persistence of model objects with your server.

This guide uses Swift Kuery ORM with Codable routes however the Swift Kuery ORM also works with Raw Routing.

Prerequisites

Step 1: Create an ORMRoutes.swift file

Open your `Sources` > `Application` > `Application.swift`

Inside the `postInit()` function add:

initializeORMRoutes(app: self)

Create a new file called `ORMRoutes.swift` in `Sources` > `Application` > `Routes`

Inside this file, add the framework for our routes code:

import KituraContracts

    func initializeORMRoutes(app: App) {
        // Connect to database here
        app.router.post("/orm", handler: app.saveHandler)
        app.router.get("/orm", handler: app.findAllHandler)
        app.router.get("/orm", handler: app.findOneHandler)
    }
    extension App {
        func saveHandler(book: Book, completion: (Book?, RequestError?) -> Void) {
            // Save book here
        }

        func findAllHandler(completion: ([Book]?, RequestError?) -> Void) {
            // Get all books here
        }

        func findOneHandler(id: Int, completion: (Book?, RequestError?) -> Void) {
            // Get one book here
        }
    }

These handlers have the same signatures as our CodableRouting handlers. Check out that guide if you would like to learn more.

Step 2: Add Swift Kuery ORM to the project

import Swift Kuery ORM to our project:

import SwiftKueryORM

To work with the ORM we need to have a Database plugin to use.

In this example we will be using SwiftKueryPostgreSQL:

import SwiftKueryPostgreSQL

You can use any database plugin but ensure that it's been added to your Package.swift.

Step 3: Update our Model

To work with Swift Kuery ORM, we need to make Book conform to the Model protocol.

We do this using an extension beneath our import statements:

extension Book: Model { }

The Model protocol extends what Codable provides to work with the ORM.

Step 4: Create a database connection

Install the PostgreSQL client

To use Swift-Kuery-PostgreSQL you need to have the appropiate PostgreSQL C-language client installed.

macOS

On macOS we can use Homebrew to install Postgres:

brew install postgresql

Linux

On Linux we can use `apt-get` to install Postgres:

sudo apt-get install libpq-dev

Create a PostgreSQL database

Now that we have PostgreSQL installed we can create a database:

createdb bookdb

Now we're ready to connect to our database from our Kitura server.

Create a PostgreSQL connection pool

Inside `initializeORMRoutes` we create a PostgreSQL connection pool:

let pool = PostgreSQLConnection.createPool(host: "localhost", port: 5432, options: [.databaseName("bookdb")], poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50))
    Database.default = Database(pool)

Create a `Book` table

Inside `initializeORMRoutes`, we create a table in the SQL database that represents our `Book` model:

do {
        try Book.createTableSync()
    } catch {
        print("Failed to create table: \(error)")
    }

To check that a database table called Grades has been created, run your Kitura server and then use psql from the command-line as follows:

psql school
    SELECT * FROM "Grades";

This should print the column names of the Grades table with no data (i.e. no rows).

Step 5: Save an Object to our database

If we want to save a new object to our database we have to use the save() method.

In our handler for the POST route we can add the following:

book.save(completion)

Because we are passing our `completion` closure to an async function, we need to make `completion` escaping:

completion: @escaping (Book?, RequestError?)

The POST handler should look similar to this:

func saveHandler(book: Book, completion: @escaping (Book?, RequestError?) -> Void) {
        book.save(completion)
    }

That's all we need to do. With that line any Book data posted to the `/orm` end point will be stored in our database.

All we need to do now is be able to retrieve data from our database.

Step 6: Retrieve all books from your database

If we want to retrieve all the Book data from our database we use the `findAll` method.

This will return an array containing the all the books.

In our `findAllHandler` add the following code:

Book.findAll(completion)

As with `saveHandler`, we must make the `completion` escaping:

completion: @escaping ([Book]?, RequestError?)

The GET handler should look similar to this:

func findAllHandler(completion: @escaping ([Book]?, RequestError?) -> Void) {
        Book.findAll(completion)
    }

Now we can test our Database using cURL to ensure everything is working correctly.

Kitura has support for OpenAPI which makes testing Codable routes easy and provides a UI for testing.

You can add OpenAPI to your server using our OpenAPI guide.

Firstly we need to start our Kitura server

Then in a terminal:

curl -X POST \
      http://localhost:8080/orm \
      -H 'content-type: application/json' \
      -d '{
        "id": 0,
        "title": "A Game of Thrones",
        "price": 14.99,
        "genre": "Fantasy"
    }'

You should see the following:

{"id": 0,"title":"A Game of Thrones","price":14.99,"genre":"Fantasy"}%

Next we can retrieve the data back.

Open your browser at:

localhost:8080/orm

This will make a get request to the server and you should see the book we posted before:

[{"id": 0,"title":"A Game of Thrones","price":14.99,"genre":"Fantasy"}]%

You can restart the server and the database will still be persisted. This is one of the many perks of using a database.

Step 7: Retrieve a single book from the database

If we want to retrieve a single Book from our database, we use the `find(id:)` method.

This will return a single object with the provided id.

In our `findOneHandler` add the following code:

Book.find(id: id, completion)

As with our previous handler, we must make the `completion` escaping:

completion: @escaping (Book?, RequestError?)

The GET one handler should look similar to this:

func findOneHandler(id: Int, completion: @escaping (Book?, RequestError?) -> Void) {
        Book.find(id: id, completion)
    }

Test this out by opening your browser at:

localhost:8080/orm/0

To view the first book you posted.

Your completed `ORMRoutes.swift` should look as follows:

import KituraContracts
    import SwiftKueryORM
    import SwiftKueryPostgreSQL

    extension Book: Model { }
    func initializeORMRoutes(app: App) {
        let pool = PostgreSQLConnection.createPool(host: "localhost", port: 5432, options: [.databaseName("bookdb")], poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50))
        Database.default = Database(pool)
        do {
            try Book.createTableSync()
        } catch {
            print("Failed to create table: \(error)")
        }
        app.router.post("/orm", handler: app.saveHandler)
        app.router.get("/orm", handler: app.findAllHandler)
        app.router.get("/orm", handler: app.findOneHandler)
    }
    extension App {
        func saveHandler(book: Book, completion: @escaping (Book?, RequestError?) -> Void) {
            book.save(completion)
        }

        func findAllHandler(completion: @escaping ([Book]?, RequestError?) -> Void) {
            Book.findAll(completion)
        }

        func findOneHandler(id: Int, completion: @escaping (Book?, RequestError?) -> Void) {
            Book.find(id: id, completion)
        }
    }
    

Next steps

Add Kitura Sessions: Store data between multiple requests from the same user.

Back to top