![Node.js logo](https://i2.wp.com/hod.greeley.org/blog/wp-content/uploads/2017/01/Node.js_logo.svg_.png?resize=360%2C220)
![Swagger Logo](https://i0.wp.com/hod.greeley.org/blog/wp-content/uploads/2017/01/Swagger-Logo.png?resize=360%2C360)
When building applications with Couchbase Mobile there are a lot of interesting possibilities for server-side integration. Creating business logic to resolve synchronization conflicts is one common use. The Sync Gateway document “changes” feed makes all sorts of event-driven operations easy to implement, too. I’ll explore this in upcoming posts.
An app can use both Sync Gateway and Couchbase Lite by directly calling the ReST API for each. That requires writing a bunch of boilerplate code that isn’t much fun, though. PouchDB offers a compatible JavaScript option, but now there’s a lighter-weight alternative.
Not too long ago Couchbase switched to using Swagger to document the Couchbase Mobile APIs. Swagger does far more than create documentation, though. With a single Swagger spec, you can generate documentation, server stub code, test cases, a sandbox site, and more. Best of all for me, Swagger can generate client SDKs… in 40 different languages!
In this post, I’m going to show how to use the Swagger Node.js client. We’ll build a super simple app that monitors changes in documents in Couchbase. This will become the basis for building some other cool stuff coming up. Let’s dive in.
What we’ll need
To follow along, you’ll want
- Node.js (I’m using v6.9.1 on a Mac)
- Swagger JS (The Swagger Node.js client)
- Couchbase Sync Gateway
- The Sync Gateway Swagger spec
I’m assuming you already have Node.js installed.
Install the Swagger JS Library
From a command line shell, change to the directory where you will keep your project.
To get the Swagger client and dependencies, run
1 |
$ npm install swagger-client |
(You will see some warnings, which you can ignore.)
Install Sync Gateway
Download the Sync Gateway package for your platform here. (If your are running Linux and don’t see a package for your distribution, see the instructions in this blog post for help.)
In order to run Sync Gateway, we need to create a configuration file. Here’s a simple setup we can use. Copy the text here and paste it into a file called “sync-gateway-config.json”, or something similar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "log": ["HTTP+"], "adminInterface": "127.0.0.1:4985", "interface": "127.0.0.1:4984", "CORS": { "origin":["*"], "loginorigin":["*"], "headers":["Content-Type"], "maxAge": 1728000 }, "databases": { "test": { "server": "walrus:", "users": { "GUEST": {"disabled": false, "admin_channels": ["*"] } } } } } |
This configuration uses a built-in database made for testing Sync Gateway. The server will only respond to connections on localhost, too. You can find resources to learn more about configuring Sync Gateway at the end of this post.
Start Sync Gateway by running
1 |
$ /path/to/sync_gateway sync-gateway-config.json |
You’ll see some logging output. You might find it interesting to watch the logs when running the app later.
Make a copy of the Sync Gateway Swagger spec
You can find the Swagger spec for the public Sync Gateway ReST APi (versus the admin API) at https://developer.couchbase.com/mobile/swagger/sync-gateway-public/spec.json. Swagger specs are stored as JSON. Although Swagger can download the text directly, it’s best to make a copy. That way if the spec changes it won’t break your app.
Copy the information into a file in your projet directory called sync-gateway-spec.json, or something similar. The file needs a .json extension for Node to process it.
Create the Node.js app
Let’s put the app together. Open up a new file in your project directory that ends with a .js extension. I used a file named app.js.
1 2 |
const Swagger = require('swagger-client'); const spec = require('./sync-gateway-spec.json'); |
The first line imports the Swagger client and makes it available. The second line is a bit more unusual. It initializes the spec
object from the JSON in the file. This is why the .json extension is important. It’s how Node recognizes we’re importing JSON, not a regular package.
The spec file has a host hardwired in, but let’s go ahead and set it ourselves.
1 2 3 4 |
const SYNC_GATEWAY_HOST = 'localhost:4984'; spec.host = SYNC_GATEWAY_HOST; |
Next, we’ll prepare the parameters for our call to the _changes
endpoint.
1 2 3 4 5 6 7 8 9 |
let query = { db: 'test', filter: 'sync_gateway/bychannel', channels: 'notification', active_only: true, include_docs: true, feed: 'longpoll', timeout: 0 }; |
Notice we have a mix here of the database name (test), which ends up being part of the endpoint URL, and some options we want to set.
Now that we’ve initialized what we need, we can create the Swagger client instance.
1 2 3 4 5 6 7 8 9 10 |
let client = new Swagger({ spec: spec, success: function() { monitor(client); }, function(error) { console.log('client error: ', error.statusText); process.exit(1); } }); |
There are several important things to note here.
We’re using the client syncronously. If you want, you can use JavaScript Promises by specifying usePromise: true
. I didn’t want to do that since I’m not doing any real processing and it complicates the code a bit.
Instead of spec: spec
, we could have listed a url for the Swagger specification using url:
. Again, you should avoid this, at least in production, because the spec could change remotely and break your code.
The success:
entry specifies two functions. Both are callbacks. The first is called if construction succeeds, the second if it fails. These are “global”, in a sense. These functions act as defaults if we don’t specify different ones to the individual calls. That’s really handy in the error case.
We assign the instance to a variable client
. The client instance is filled out asynchronously. It isn’t ready to use until the success callback happens. So we have the interesting construct that client
is used internally in the callback. In the Promises version, client would be passed as the argument in the .then
clause.
In the next part of the code, we use the client to listen to the _changes
endpoint.
1 2 3 |
function monitor(client) { client.database.get_db_changes(query, message); } |
This presents a problem: how do we find out the name of the function we want to call? There’s no fixed mapping between endpoints and functions names. This is another handy feature of Swagger. The client class is self-documenting. You call help()
at whatever level you need. For example, to find out about endpoints under database, add this in your code:
1 |
client.database.help(); |
The help output shows up in the command line output (or your IDE’s console). It will describe the endpoints and all the possible parameters.
Going back to the client call, we see that we passed both the database name (required), and several parameters in lumped together in the query
object. This was a little confusing. You might expect these to be separated out, but that won’t work. None of the examples I found explained this.
We supplied a callback function message
. (Notice that’s used if the ReST call succeeds. We rely on the default to handle failures.)
1 2 3 4 5 |
function message(response) { console.log(response.data); query.since = response.obj.last_seq; monitor(client); } |
The callback receives an object containing all the details of the response. I just wrote this app to show the loop structure needed to listen to the Sync Gateway changes feed. Hence, the message
function doesn’t do much. We write the call response out for debugging purposes. We then want to go back and listen for the next update. Sync Gateway knows what to push based on sequence IDs. To control that, we use the last_seq
information from our last response.
That’s it. Here’s the complete code for the app.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const Swagger = require('swagger-client'); const spec = require('./sync-gateway-spec.json'); const SYNC_GATEWAY_HOST = 'localhost:4984'; spec.host = SYNC_GATEWAY_HOST; let query = { db: 'test', filter: 'sync_gateway/bychannel', channels: 'notification', active_only: true, include_docs: true, feed: 'longpoll', timeout: 0 }; let client = new Swagger({ spec: spec, success: function() { monitor(client); }, function(error) { console.log('client error: ', error.statusText); process.exit(1); } }); function monitor(client) { client.database.get_db_changes(query, message); } function message(response) { console.log(response.data); query.since = response.obj.last_seq; monitor(client); } |
Final notes
You can fire up your app and try it out. Make sure Sync Gateway is running. Then run
1 |
$ node app.js |
You should see a response in the Sync Gateway logs and something like this output by the app itself:
1 2 3 4 |
{"results":[ {"seq":1,"id":"_user/GUEST","changes":[]} ], "last_seq":"1"} |
Now, add a new document. You can do this with cURL on the command line. Here’s an example.
1 |
$ curl -X PUT -H "Content-Type: application/json" -d '{ "key": "value", "channels": "notification" }' http://localhost:4984/test/doc |
Your Node app should output something like this:
1 2 3 4 |
{"results":[ {"seq":2,"id":"doc","doc":{"_id":"doc","_rev":"1-d0efa985de274451fc7cdcf471152ce2","channels":"notification","key":"value"},"changes":[{"rev":"1-d0efa985de274451fc7cdcf471152ce2"}]} ], "last_seq":"2"} |
Other Resources
Read more about Couchbase Mobile.
Read about the Sync Gateway ReST APIs.
The Swagger JS client GitHub respository has some useful documentation included.
Find out about Swagger itself at http://swagger.io.
The online Swagger editor is really useful. You can generate client SDKs here, or even try out the API directly. Just paste the Swagger spec into the editor. http://editor.swagger.io/
There’s a React Native Couchbase community project that uses the JavaScript client. You can find some interesting examples there at https://github.com/couchbaselabs/react-native-couchbase-lite
This post originally appeared on http://blog.couchbase.com/.