MongoDB Stitch is MongoDB's backend-as-a-service solution. Stitch supports a wide variety of high-level features, like Twilio integration and field-level access control, but it also supports custom functions similar to Amazon Web Services' Lambda. In this article, I'll walk you through setting up backend application in MongoDB Stitch on top of MongoDB Atlas. This backend application regularly ingests stock price data from the IEX API and exposes an REST API endpoint for loading a stock's latest price.

Ingesting Stock Data

This article assumes that you already have a MongoDB Atlas cluster running and have Node.js installed. See this guide if you don't have a MongoDB Atlas account yet.

Log in to MongoDB Cloud. Look for "Linked Stitch App". If you don't have one yet, click "Link Application" to create a new Stitch app.

Name your app "stocks" and click "Create".

Once Stitch has created your app, leave authentication off for now, and add a collection with database name 'test' and collection name 'prices' to your Stitch app.

Next, click on "Functions" on the navbar to create your first Stitch function.

Click "Create Function" to open up the function editor. Name the function "ingest", leave it public, and leave "Can Evaluate" blank, then click "Save".

In order to actually run a Stitch function, you need to create a Stitch user. Click "Users" on the navbar, then click "Providers" to see a list of all user providers. Edit the "API Keys" provider.

Enable the API Keys provider and click "Create API Key" to create a new API Key. Click "Save" and copy the newly generated API Key somewhere safe.

Next, click "Services" and add an HTTP service. Call this service "http".

Next, go to your cluster under "Atlas Clusters", click the "test.prices" collection, and convert all field rules and filters to empty objects. This will remove all access controls so your functions can read from and write to the "test.prices" collection without restriction.

Now that your Stitch functions have unrestricted read/write access, go back to the ingest() function and enter in the below source code. Stitch's JavaScript runtime is not Node.js, so you can't require() npm modules, but you can access services, like the HTTP service you defined, from the global context object.

The below function gets a connection to your Atlas cluster and an HTTP client from the context object. It then uses the http client to get the current price of MongoDB stock and stores it in the prices collection.

exports = function(symbol) {
  const atlas = context.services.get('mongodb-atlas');
  const http = context.services.get('http');

  symbol = symbol || 'MDB';

  return http.get({ url: `https://api.iextrading.com/1.0/stock/${symbol}/price` }).
    then(res => parseFloat(res.body.text())).
    then(price => atlas.db('test').collection('prices').insertOne({
      symbol,
      price,
      time: new Date()
    }));
};

In order to run your function, you need to click on the "Console" tab in the bottom, change the parameter from 'Hello World' to 'MDB', and select a user. Stitch functions always run in the context of a user, so select the testkey user. Then, click "Run Function As" to execute your function. You should get the below output.

Now, connect to your MongoDB Atlas application with the MongoDB shell and query the prices collection, you should see an entry that contains the current price of MongoDB stock.

$ /mongo "mongodb+srv://cluster0-OMITTED.mongodb.net/test" --username OMITTED
MongoDB shell version v4.0.0-rc2
Enter password:
connecting to: mongodb+srv://cluster0-OMITTED.mongodb.net/test
shard-0:PRIMARY> db.prices.find()
{ "_id" : ObjectId("5b19725eb8b9985731acddb3"), "symbol" : "MDB", "price" : 49.12, "time" : ISODate("2018-06-07T17:58:54.155Z") }
shard-0:PRIMARY>

MongoDB Stitch currently does not support running functions on a timer, so you'll have to expose the function via HTTP and trigger the function by sending an HTTP request every minute. But first, let's write the function that gets the latest stock price and then create webhooks for both functions.

Stock Price REST API

In order to create an API endpoint that returns the latest stock price, you'll need a separate Stitch function read(). Click on the "Functions" tab and create a new function named "read", and leave it public.

Click on "Function Editor" and enter in the below source code. Stitch currently doesn't support findOne() with sort, so the below function uses the Atlas service's find() function to get the most recent stock price for the given symbol.

exports = function(symbol) {
  const atlas = context.services.get('mongodb-atlas');

  return atlas.db('test').collection('prices').
    find({ symbol }).
    sort({ time: -1 }).
    limit(1).
    toArray().
    then(res => Array.isArray(res) ? res[0] : null);
};

Click "Run Function As" and you should see the document your ingest() function inserted in MongoDB Extended JSON format.

Now that you have a read() function, let's create a webhook that runs the read() function when an HTTP request comes in. Click on "Services" in the navbar, then click the "http" service, and click "Create New Webhook". Name the webhook "read", turn on "Respond with Result", and configure it to respond to GET requests. Enable the "Require Secret as Query Param" option and enter in a secret string. Then, click "Save".

Now, go to the "Function Editor" tab and enter in the below source code for your webhook. Webhooks have their own custom function logic, but you can call Stitch functions from other Stitch functions using context.functions.execute() with the function name.

exports = function(payload) {
  const symbol = payload.query.symbol || 'MDB';
  return context.functions.execute('read', symbol);
};

Now, click on the "Settings" tab to find the URL for your Stitch webhook. Copy the webhook URL.

You should now be able to use access your webhook using an HTTP client like curl. Make sure you add secret as a query parameter as shown below, otherwise you'll get an authentication error. Unlike Lambda, Stitch functions require authentication.

$ curl https://webhooks.mongodb-stitch.com/api/client/v2.0/app/stocks-OMITTED/service/http/incoming_webhook/read?secret=OMITTED
{"_id":{"$oid":"5b19725eb8b9985731acddb3"},"symbol":"MDB","price":{"$numberDouble":"49.12"},"time":{"$date":{"$numberLong":"1528394334155"}}}
$

You still need one more webhook for the ingest() function, so go back to the "Services" view, click on "HTTP", and click "Add Incoming Webhook" to create another webhook.

Name this webhook "ingest", have it respond to POST requests, and give it a different secret. Then, click "Save".

Next, in the function editor, enter in the below code. Like the read() webhook, the ingest() webhook just calls the ingest() function.

exports = function(payload) {
  const symbol = payload.query.symbol || 'MDB';
  return context.functions.execute('ingest', symbol);
};

Once you click "Save", you should be able to access the ingest() function using an HTTP client like curl.

$ curl -X POST https://webhooks.mongodb-stitch.com/api/client/v2.0/app/stocks-OMITTED/service/http/incoming_webhook/ingest?secret=OMITTED
{"insertedId":{"$oid":"5b1983cdb8b9985731e9623e"}}
$

Connect to your MongoDB Atlas cluster and you should see a new document in the prices collection. You would have to use a service like Lambda or Metronome to call your Stitch webhook on a timer.

$ /mongo "mongodb+srv://cluster0-OMITTED.mongodb.net/test" --username OMITTED
MongoDB shell version v4.0.0-rc2
Enter password:
connecting to: mongodb+srv://cluster0-OMITTED.mongodb.net/test
shard-0:PRIMARY> db.prices.find()
{ "_id" : ObjectId("5b19725eb8b9985731acddb3"), "symbol" : "MDB", "price" : 49.12, "time" : ISODate("2018-06-07T17:58:54.155Z") }
{ "_id" : ObjectId("5b1983cdb8b9985731e9623e"), "symbol" : "MDB", "price" : 50.225, "time" : ISODate("2018-06-07T19:13:17.198Z") }
shard-0:PRIMARY>

That's all you need to set up a backend application with MongoDB Stitch. Stitch has a few limitations, like no support for automatically running a function every minute, but the JavaScript code is concise and you don't have to worry about managing a database connection. Once you get familiar with the Stitch UI, writing custom JavaScript functions is easy.

Moving On

MongoDB Stitch provides an interesting alternative to AWS Lambda and Azure Functions if you're already using MongoDB Atlas. The downside is that Stitch uses its own JavaScript runtime, so you can't use Node.js modules like moment. But, Stitch gives you a lot more features out of the box, like built-in access control and database connection management. Next time you think about working with cloud functions, give MongoDB Stitch a shot.

Found a typo or error? Open up a pull request! This post is available as markdown on Github
comments powered by Disqus