Why CouchDB + Guzzle?

Apache CouchDB™ is a document database, which means it’s a great addition to your application if you want to store data that could be complex or of varying shapes and sizes. CouchDB is super-flexible and easy to work with. It stores data in JSON format, and you write your queries/views using JavaScript. Best of all, the interface is simple HTTP, which means you can talk to CouchDB directly with familiar tools, and it’s easy to add the database into your application regardless of the technology stack you use.

In today’s post, we’ll look at how we can use CouchDB in our PHP applications, using the excellent PHP HTTP library Guzzle. Guzzle is a modern, PSR-7 compliant object-oriented PHP library that handles all aspects of HTTP in a correct and — importantly, a scalable — way. So it’s a great way to add any HTTP-interfaced services into your application (PHP 5.5 and later, does support PHP 7).

CouchDB and Guzzle logos on a tennis ball

Whether you’re running CouchDB locally or using a hosted service like Cloudant, you have easy access to a great admin interface for CouchDB called Fauxton. If you’re a fan of tools like PHPMyAdmin that provide an easy, human-friendly view of what’s happening in your database, then definitely check it out.

Screenshot of Cloudant dashboard, similar to CouchDB Fauxton web interface
An empty Cloudant dashboard. The CouchDB Fauxton admin interface looks similar. Let’s fill out this dashboard by creating a database!

First Step: Connect to CouchDB

We mentioned that CouchDB has a simple HTTP interface, and that means you can make a basic curl request to it and it will respond. This URL is all we need to begin to use CouchDB from our PHP applications. If you’re running locally, then the URL is http://127.0.0.1:5984/. For Cloudant on IBM Bluemix, you can find the details in the “Service Credentials” section, and the URL looks something like https://[username]:[password]@[hostname]-bluemix.cloudant.com.

Locating Cloudant credentials in IBM Bluemix
Finding your Cloudant creds in IBM Bluemix.

We’ll also need to add the Guzzle library into our project using Composer by doing:

composer require guzzlehttp/guzzle:~6.0

This brings the dependency into our project (the code is now in the vendor/ folder and should be ignored by your source control tool). To make it available to PHP we will add the composer autoloader at the top of all our scripts by adding this line:

require 'vendor/autoload.php';

We’re all set! Let’s make a first request to CouchDB using Guzzle, and inspect the output. Here’s a PHP script to do that:

<?php
require 'vendor/autoload.php';

$url = ""; // edit this line!  Put your URL here

try {
    $client = new \GuzzleHttp\Client(["base_uri" => $url]);
    $response = $client->request("GET", "/");
    if($response->getStatusCode() == 200) {
        echo $response->getBody();
    }
} catch (\GuzzleHttp\ExceptionRequestException $e) {
    // couldn't connect
} catch (\GuzzleHttp\ExceptionClientException $e) {
    // 400-class error
} catch (\GuzzleHttp\ExceptionServerException $e) {
    // 500-class error
}

The output I get from running this on my system is:

{"couchdb":"Welcome","version":"1.0.2","cloudant_build":"2580"}

Included in the example above are some catch statements which will allow you to react to the various error states that come out of Guzzle. To keep the examples short, we’ll focus on the part inside the try{} block in our future examples, but it’s recommended to continue to set up your code as shown in the full example here and to add detail to the exception cases to help with logging and debugging in your application.

Working With Databases

Getting a list of databases from CouchDB is simple — you might choose to set these up in your init script or even manually using the web interface — but while we’re getting to know CouchDB, we’ll do this programmatically.

Getting the list of databases is done by making a GET request to /_all_dbs. You’ll notice a few of these special URLs starting with an underscore as we do a few different things with CouchDB. Here’s some PHP code to get that list of databases (use the same $client you created in the previous example):

    $response = $client->request("GET", "/_all_dbs");
    if($response->getStatusCode() == 200) {
        echo $response->getBody();
    }

At this point, you may notice that this returns an empty list (depending on your installation, some do set up databases for you) …

… so let’s add some databases. CouchDB’s HTTP interface uses HTTP verbs to convey to the server what action should take place. To create a new named database, the PUT method is used on the URL where the database itself will live. For example, to create a database called "items", a PUT request can be made to /items.

Here’s the PHP code to create that "items" database:

    $response = $client->request("PUT", "/items");
    echo $response->getStatusCode() . ": " . $response->getBody();

Notice that this time, the code doesn’t expect a 200 status code. That’s because when something is created, the server will return the HTTP 201 status code (which literally means created). Repeat your earlier script to list the databases and you should see that “items” now appears in the list.

If you try to create a database that already exists, you will cause an error. One of the nicest things about Guzzle is the way that all errors come back to the user as Exceptions, so the developer can see what happened and decide how the application should respond. For a database that already exists, Guzzle will emit a RequestException because the response has a status code of 412, which means “Precondition failed”. This is accompanied by a longer message in the body of the response which lets you know that the DB already exists.

Inserting and Selecting Data

Now that there is a database to put things in, it is time to work with individual records. These examples are intentionally kept simple, but the same principles apply as you expand the size and complexity of the data sets as your applications (and your ambitions) grow.

Let’s begin by putting a very simple record into our items collection. You can put anything you like into these records really; CouchDB is just JSON storage. Here’s some PHP to create a record:

    $data = [
        "type" => "tennis ball",
        "color" => "yellow",
        "tags" => ['sport', 'summer', 'tennis']
    ];

    $response = $client->request(
        "POST",
        "/items",
        [
            "json" => $data
        ]
    );
    echo $response->getBody();

Guzzle has a "json" option parameter that will json_encode() the value that you supply and add the appropriate Content-Type: application/json header as well. You could equally set the body to a json-encoded string and manually set the header, but this approach is a shorthand to the same outcome.

When using the code above, CouchDB will return an OK status, the ID of your new record and a revision (more on that later). You can also go and view the data in the web dashboard. Notice that by default you only see the metadata related to a record, not the record itself. To see the data as well, tick the “docs” or “include docs” checkbox at the top.

Example document in the Cloudant web dashbaord
Game, set, match — our tennis ball document, residing in our items database.

We’ll also want to fetch these records programmatically, so here’s the same dataset being retrieved with PHP:

    $response = $client->request(
        "GET",
        "/items/_all_docs",
        ['query' => ['include_docs' => 'true']]
    );
    if($response->getStatusCode() == 200) {
        echo $response->getBody();
    }

Here we’re using another special URL, _all_docs to get all the records in this database. Exactly as was shown in the screenshot above where it’s an extra step to include the document itself, here the include_docs query parameter needs to be set to true to get that data as well.

Updating and Deleting Data

The approach for updates and deletes is very similar — and they require one extra step that we haven’t seen before that stems from CouchDB’s superpowers. CouchDB is designed to be resilient across network failures, including if part of a database cluster goes offline and both sides of the separated network are written to. This means that when we operate on existing records, either to update or delete them, we need to indicate which version of the record we had when we made this change or requested this delete.

We’ll look at the delete example as the code is simpler simpler (for updates the only difference is that the PUT verb is used and data is supplied in the same way as when we inserted a record). To delete a record, the DELETE verb should be used, and the revision that we are trying to delete must also be supplied. In most cases, we will first fetch the record to get that information.

Here is the PHP code for fetching and then deleting a record, supplying the revision information:

    $response = $client->request(
        "GET",
        "/items/_all_docs",
        ['query' => ['include_docs' => 'true']]
    );
    if($response->getStatusCode() == 200) {
        $items = json_decode($response->getBody(), true);
    }

    // just delete whichever item got returned first
    // normally we'd be doing a specific query above
    $item = $items['rows'][0];

    var_dump($item);
    $response_delete = $client->request(
        "DELETE",
        "/items/" . $item['id'],
        [
            "query" => ["rev" => $item['value']['rev']],
        ]
    );
    echo $response_delete->getStatusCode() . ": " . $response_delete->getBody();

This example shows how to use both the ID to create a URL and the revision to add as a query parameter when making the DELETE request so that we can delete a specific option. If the query is run without the ?rev=, it will fail with a status code of 409 meaning “Conflict”. When making updates or deletes, CouchDB always expects the revision to be sent so it knows which version of the record is being operated on, and it can therefore handle conflicts when syncing data stores that may have been offline (but still in use) for some time. For futher reading on CouchDB’s magical replication & synch abilities, try this article about consistency in CouchDB or check out the technical overview of CouchDB (some absolute gems scattered in there if you keep reading).

PHP, Guzzle and CouchDB

This winning combination of modern technologies is a nice way to work with data from a PHP application. CouchDB is an excellent document datastore, and its very standard HTTP interface makes it easy and fast to work with. You don’t need special tools or extensions, and PHP developers have a pretty solid grasp of HTTP already, which means there are no new skills needed for working with or debugging this stack. Guzzle is best-of-breed in HTTP libraries for PHP, and combined with CouchDB it’s a combination ready for anything!

4 comments on"Get Started With CouchDB Using PHP and Guzzle"

  1. […] the IBM Developer Blog they’ve posted a new article from Lorna Mitchell helping you get started with CouchDB and Guzzle, making use of this popular HTTP client package to interface with CouchDB’s HTTP interface […]

  2. […] the IBM Developer Blog they’ve posted a new article from Lorna Mitchell helping you get started with CouchDB and Guzzle, making use of this popular HTTP client package to interface with CouchDB’s HTTP interface […]

  3. […] the IBM Developer Blog they’ve posted a new article from Lorna Mitchell helping you get started with CouchDB and Guzzle, making use of this popular HTTP client package to interface with CouchDB’s HTTP interface […]

  4. […] articles and videos to get you started! Get started with “GraphFrames in Apache Spark” and “CouchDB Using PHP and Guzzle” Chalk Talk: How data can be turned into insights. Mike Broomhead gives an overview of the analytics […]

Join The Discussion

Your email address will not be published. Required fields are marked *