Currently in Beta - View old docs

Kitura CouchDB

CouchDB is a NoSQL (or non-relational) database. CouchDB takes a document-oriented approuch to databases.

Kitura-CouchDB is a pure Swift client which allows Kitura applications to interact with a CouchDB or Cloudant database.

Prerequisites

  • Kitura Server: Learn how to create one in our getting started guide
  • Routing: Learn how to add routes in our routing guides
  • Update Dependencies: Kitura CouchDB needs adding to the Package.swift file.

Step 1: Download and install CouchDB

Before we can use CouchDB within our server we first need to Download CouchDB.

Step 2: Create CouchDB admin user

Once CouchDB is installed we need to create an admin user.

To do this we need to open the CouchDB admin console:

macOS:

Select the CouchDB icon in the menu bar.

Then select open admin console from the drop down.

If this is your first time opening CouchDB then you'll be greeted with a create admin user screen.

If you've used CouchDB then simply log in to the account you wish to use.

It is important to remember the creditials we used here as we will need them to interact with the database from our server.

Step 3: Create CouchDB database

We can create a database directly through the CouchDB admin console.

First ensure we're logged in and then select the database icon from the sidebar.

Then in the top right click on `Create Database`

We'll be asked to provide a name, for our example we will call it: `bookstore`

Step 4: Create an CouchRoutes.swift file

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

Inside the `postInit()` function add:

initializeCouchRoutes(app: self)

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

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

import KituraContracts
    import CouchDB
    import LoggerAPI

    func initializeCouchRoutes(app: App) {
        // Connect to database here
        app.router.post("/couch", handler: app.couchSaveHandler)
        app.router.get("/couch", handler: app.couchFindAllHandler)
    }
    extension App {
        func couchSaveHandler(book: Book, completion: (Book?, RequestError?) -> Void) {
            // Save book here
        }

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

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

Step 5: Connect to CouchDB database

Inside our app extension, we define our connection properties for CouchDB:

static let properties = ConnectionProperties(
        host: "127.0.0.1",              // http address
        port: 5984,                     // http port
        secured: false,                 // https or http
        username: "<CouchDB-username>", // admin username
        password: "<CouchDB-password>"  // admin password
    )

Now we can use these properties to create our CouchDB connection:

static let couchDBClient = CouchDBClient(connectionProperties: properties)

Step 6: Define our BookDocument

Create a new file called `BookDocument.swift` in `Sources` > `Application` > `Models`.

Inside this file, Define your BookDocument class:

import CouchDB

    struct BookDocument: Document {
        let _id: String?
        var _rev: String?
        var value: Book
    }

Step 7: Save our Document to our database

To save data to our CouchDB database we first need some data to save, this data can be provided by a POST route.

So we will need to modify our couchSaveHandler to store data in our database:

func couchSaveHandler(book: Book, completion: @escaping (Book?, RequestError?) -> Void) {
        App.couchDBClient.retrieveDB("bookstore") { (database, error) in
            guard let database = database  else {
                return completion(nil, .internalServerError)
            }
            let bookDocument = BookDocument(_id: String(book.id), _rev: nil, value: book)
            database.create(bookDocument) { (response, error) in
                if let error = error {
                    Log.error(error.localizedDescription)
                    return completion(nil, RequestError(httpCode: error.statusCode))
                }
                guard response != nil else {
                    Log.error("Unknown CouchDB Error")
                    return completion(nil, .internalServerError)
                }
                completion(book, nil)
            }
        }
    }

Step 8: Retrieve from CouchDB database

To retrieve all documents from a CouchDB database we need to use the aptly named `retrieveAll` method within our `couchFindAllHandler`:

func couchFindAllHandler(completion: @escaping ([Book]?, RequestError?) -> Void) {
        App.couchDBClient.retrieveDB("bookstore") { (database, error) in
            guard let database = database  else {
                return completion(nil, .internalServerError)
            }
            database.retrieveAll(includeDocuments: true, callback: { (allDocuments, error) in
                if let error = error {
                    Log.error(error.localizedDescription)
                    return completion(nil, RequestError(httpCode: error.statusCode))
                }
                guard let allDocuments = allDocuments else {
                    Log.error("Unknown CouchDB Error")
                    return completion(nil, .internalServerError)
                }
                let books = allDocuments.decodeDocuments(ofType: BookDocument.self).map({$0.value})
                completion(books, nil)
            })
        }
    }

Next steps

Add logging: Get useful feedback from your server about startup and errors

Add routing: Add REST APIs, such as HTTP GET, to your server

Back to top