Writing server-side code in Azure Cosmos DB

Microsoft brings stored procedures and triggers to cloud-scale storage with an integrated JavaScript API

Writing server-side code in Azure Cosmos DB
Getty Images

Azure Cosmos DB, Microsoft’s cloud-scale distributed database, is designed to offer the APIs and the storage model you need for your applications. Want a NoSQL database? Use the MongoDB or Cassandra APIs. Need to work with graph queries? Use the Gremlin API. Azure’s own table storage APIs? They’re in there too. There’s even the option of using SQL.

But that’s only the outside of Cosmos DB, its connection to the rest of your application. In many cases you’ll need to add more code to manage your data and provide basic processing inside the database. Traditional databases offer stored procedures and triggers to manage this, running server-side code close to your data.

Going server-side in Cosmos DB

It’s no surprise that Cosmos DB supports server-side code, with a built-in set of JavaScript APIs that run transactional code inside the database, much like your SQL Server stored procedures. However, building and running those stored procedures is rather different and requires some thought. You’re no longer working with one database on one server (or at most, a small local cluster). Now you’re working with distributed stores that may be continents apart and use new consistency models. These models are more predictable than eventual consistency but don’t offer the locks that are required by strong consistency models.

At the heart of Cosmos DB’s stored procedures is its integrated JavaScript query API. Procedures get access to standard database operations to create new items and read, update, delete, and query existing items. They work inside Cosmos DB containers and are registered to specific collections in your database.

Using the JavaScript Query API

Building Cosmos DB JavaScript is easy enough. It’s much like working with any server-side JavaScript environment, so you can bring existing skills to Cosmos DB development. Your code will need to create a context object using the getContext() function, as this gives you access to your database and any available operations, including request and response. Cosmos DB-specific constraints on your code will require you to focus on writes for server-side code. Stored procedure and trigger code runs in the primary replica of your Cosmos DB storage container; user-defined function queries run on primary and secondary replicas.

The JavaScript Query API works with either Cosmos DB’s SQL API or with its own set of function calls. The JavaScript API uses functions to host queries, working with stored JSON documents and with Cosmos DB’s indices. You can treat functions such as filter() and map() much like familiar SQL commands, with filter() operating like WHERE and map() like SELECT. If you’ve used Microsoft’s Linq in-line query language with C#, you’ll find the query API works in a similar manner. If you prefer SQL your queries can be written like any other SQL query: defined as strings in your JavaScript and passed to Cosmos DB as part of a query call against the documents in a container.

It’s important to remember that Cosmos DB is a distributed database, and it will manage data across multiple instances and containers, so you’ll find that all your data operations are asynchronous, taking advantage of JavaScript callbacks for server responses. Your callbacks should include error-handling code, or errors will trigger Cosmos DB’s own error-handling features. There’s another important consideration: Cosmos DB enforces timeouts, and if a procedure takes too long to run, it will be treated as a failure and the transaction will be rolled back by the database.

Stored procedures in Cosmos DB

Stored procedures are built as JavaScript functions, and items to be inserted into databases will be passed to the function as a string containing JSON content. You will need to parse the JSON to get other data types, such as array contents. JavaScript handles JSON easily, and the request string contents map to JavaScript types.

Once your stored procedures have been written and installed in your database, you can call them from your applications like any other Cosmos DB function. You’ll first register the procedure and then call it by constructing the appropriate URI and delivering JSON to it. The request body will need a partition key, as stored procedures are scoped to specific partition keys. When data is written to the database it’ll be replicated using your chosen consistency model.

Triggers and user-defined functions

Cosmos DB supports triggers, both pre- and post-triggers. Your applications will use pretriggers before an item is modified; post-triggers will run afterward. One use for pretriggers is validating items before they’re written to Cosmos DB: checking that inputs are within bounds or adding expected information if it’s not present in the initial operation. You won’t pass parameters to a trigger, as all you’re doing is working with the contents of the request object. Similarly post-triggers can take data from an object that’s been modified, using it to update either metadata or other documents in the Cosmos DB store.

Triggers are written in a similar manner to stored procedures, using the JavaScript query APIs and the getContext() function. Like all operations using the JavaScript API, Cosmos DB triggers are transactional; an error in a post-trigger will roll back the current transaction, generating a Cosmos DB exception. Failures in a pretrigger will mean that the current action won’t make any changes to the database.

The other option for server-side code is user-defined functions, a way of using reusable pieces of code that can be added to your Cosmos DB database and then called by triggers or stored procedures. One typical use is for common calculations where additional data is stored based on function results, such as working with mileage allowances and expense rules, or calculating the sales tax to add to a purchase.

Cosmos DB is a powerful tool and adding code to it makes it even more useful. If you’re using it with a web or mobile app, offloading compute to the database makes sense, especially if you’re adding calculated data to a document or storing metadata for a request. Code doesn’t need to be complex, though coming to grips with Cosmos DB’s context model can take some work if you haven’t used in-line query languages such as .Net’s Linq.

Copyright © 2019 IDG Communications, Inc.