Many developers like the simplicity and flexibility provided by specialised document databases. These systems offer a lot of freedom when it comes to writing applications. If you don’t like SQL, a Document API provides another way to persist data. There is no better or worse approach. Developers should be empowered to use the technology they are most comfortable with unless the choice of technology violates other requirements like availability, security, etc.
Modern databases like Oracle don’t require you to make compromises, though. You get the best of all worlds with a converged database.
Document APIs and Converged Databases
For a very long time, Oracle has provided a Document API named SODA—short for Simple Oracle Document Access. Oracle also supports the Mongo DB protocol in the form of Oracle Database API for MongoDB.
In addition to these two, Oracle Database 23ai introduced JSON Relational Duality Views, blurring the borders between relational and document worlds.
SODA offers drivers for popular client languages like JavaScript, Python, and many others.
A Document API, but this time, it’s executed directly on the database server
In addition to the aforementioned client-side drivers, developers have another option: using a Document API in server-side languages.
Running code on the database server has many advantages. For starters, you are guaranteed not to suffer from latency introduced by round-trips from client to server. Others have been documented elsewhere if you are interested. Server-side languages, however, aren’t the most fashionable way to code. This is where a new feature in Oracle Database 23ai on Linux might help.
Oracle Database 23ai introduced Multilingual Engine(MLE), offering another server-side programming language: JavaScript. JSON and JavaScript go hand in hand, and it is very easy to use a Document API with MLE.
JavaScript and Document API example
Let’s assume a typical use case where an application POSTS a JSON payload to the backend. This is straight-forward with Oracle technology:
- You start a container running Oracle REST Data Service (ORDS) to receive GET, PUT, POST, DELETE, etc. requests. There is no need to hand-craft any of that, and in particular, there is no need to implement authorisation and authentication as you do in node-express and its friends.
- ORDS is already connected to the database. You tell it what to do when a POST request comes in.
- You can tell ORDS to use a Document API to persist the POST request.
Here is a quick example of how to use the Document API to interact with JSON data in MLE/JavaScript. From the code alone, it is not possible to tell if this runs on the client or server.
/**
* Retrieve a purchase order by ID
* @param {number} id the purchase order's ID
* @returns {object} the purchase order as retrieved from the database
* @throws an exception if the collection cannot be opened for reading
*/
export function getPurchaseOrder(id) {
const collection = soda.createCollection("exampleCollection");
if (collection === null) {
throw new Error("failed to open the collection for reading");
}
const data = collection.find().filter({ _id: id }).getOne().getContent();
return data;
}
/**
* Process a purchase order
* @param {object} po the purchase order to process
* @throws an exception if the validation fails
*/
export function savePurchaseOrder(po) {
// simulate some kind of validation. Assume, for example,
// you need at least one line item and a customer name
// this would be more sophisticated in real life.
if ("customer" in po && po.lineItems.length > 0) {
const collection = soda.createCollection("exampleCollection");
collection.insertOne(po);
} else {
throw new Error("error storing the purchase order: document failed validation");
}
}
If you have used a document API before, these are probably quite familiar. Oracle JavaScript Developer’s Guide features an entire chapter on the SODA API if you would like to explore it more.
Testing
Once this JavaScript module is loaded into the database, and exposed as GET and POST handler by ORDS, you can call it from any client you like. Since curl is ubiquous, it’s used here. But this is equivalent to your Angular, React, Vue, Django, Flask, J2EE application: they’d all make the same REST call via fetch() or equivalent call.
Insert a new JSON first:
curl --json '{
"_id": 1,
"address": {
"city": "Frankfurt",
"country": "DE",
"post_code": "60311",
"street": "Neue Mainzer Strasse 46-50"
},
"customer": "some customer",
"lineItems": [
{
"item_no": 1,
"product": "abc",
"quantity": 10
},
{
"item_no": 2,
"product": "xyz",
"quantity": 20
}
]
}' https://localhost:8181/ords/martin/api/orders/
After which you can query it, assuming this was the first record inserted:
curl https://localhost:8181/ords/martin/api/orders/1
The output is the same as the input, which is why it’s not shown here.
Summary
The best thing about modern IT is choice. Developers can pick whichever solution they are most comfortable with for their projects. As you can see from the code example in this article, modern converted databases can support a great many workloads in many languages and formats.
