REST-like API vs Drivers
The most common way of accessing data from your projects has traditionally been using drivers. MongoDB has drivers for many different programming languages. These allow you to call various functions, including covering the Create, Read, Update, Delete [CRUD] operations, from within your project in the language of your choice.
We have many articles on how to get up and running using MongoDB drivers for your language of choice. So if you wish to use drivers, this is still a valid option.
Below is a list of some existing tutorials using current drivers, potentially in your language/framework of choice:
- Express.js and MongoDB REST API Tutorial
- How to Use MERN Stack: A Complete Guide
- TypeScript Integration with MongoDB Guide
- How to use MongoDB Atlas with .NET/.NET Core
- Build a RESTful API with Flask, MongoDB, and Python
However, there are times when you might not want to use a driver—for example, if it is a purely command-line based application or script, such as one that relies on cURL for sending REST or GraphQL requests via HTTP.
Installing drivers and creating endpoints for your application that can make calls to the database can take time, and if you have a very simple use case, such as just CRUD, this extra overhead is unnecessary. This is where the new MongoDB Atlas Data API comes in.
Using the new Atlas Data API from different languages
As well as cURL, you can call the Data API from a variety of languages. All it needs is a way to make HTTP calls.
In fact, in Atlas, we even give you code snippets in different languages, right from the UI, to get you started making calls to find a document.
- Click the “Data API [Preview]” option from the left-hand sidebar.
- Click the “Test Your API” button in the top right corner.
- Select your Cluster, Database, and Collection from the dropdown menus, and then select the language that you want from the dropdown box at the bottom.
Learn more about other operations, such as writing a document, you can make in our Data API documentation.
Summary
In this article, you have learned about how you can get started today with the new Atlas Data API, without needing to create your own endpoints. When you don’t require a full application, just the CRUD operations, the Atlas Data API gets you started with ease in just a few minutes. You can even get help from the Atlas UI to get you kickstarted with code snippets for your favourite language.
FAQ
Does MongoDB have a REST-like API?
Building a REST API with Express, Node, and MongoDB
Follow along with this tutorial to add MongoDB Atlas as the data store for your applications, by creating NodeJS and Express Web REST API.
The Project Architecture
You can explore the full project in the following GitHub repo:
- main branch - finished project
- stub branch - starting point for following this tutorial
Express allows us to create a back-end middle tier running Node.js server exposing REST API routes to our application.
The Express.js server also connects to the MongoDB Atlas cluster via the Node.js Driver. If you wish to learn more about MongoDB and Node.js, read the following article.
Finally, our front-end application will be written in React to use the REST API endpoints hosted on the Express.js server. The application is a Tinder-like application for the sample_airbnb database, containing information on various listings, available as part of the sample datasets you can load into the Atlas cluster.
Users can swipe the listing cards to save or drop them and press the “like” button to add likes. Additionally, a double click will show details about the specific listing card presented.
Project Tree
Here are the main files in the project:
- server/
- db
- conn.js
- routes
- record.js
- server.js
- config.env
- db
- app/listings/
- public/
- src/
- App.js
- App.css
- index.js
The “server” directory hosts the Express.js server application and all of its dependencies. The main files here are:
- “db/conn.js”: Exposes a global connection to the Atlas database by exporting a MongoDB client that any other module can use.
- “routes/record.js”: Exposes the REST API endpoints and performs their business logic against the Atlas cluster.
- “server.js”: The main entry point for the Express server and configuration initialization.
- “config.env”: Configuration file holding Atlas connection string details.
The “app/listings” directory is where the front-end React application code resides. The main files here are:
- “App.js/App.css”: Front-end React code to render the app and interact with the Express REST API endpoints.
- “index.js”: The main entry point for the React web app importing the App.js.
Setting Up the Project
First, you will need to deploy an Atlas cluster. You can follow the Getting Started with Atlas guide to learn how to create a free Atlas account, create your first cluster, and get your connection string to the database.
Once we have the Atlas cluster available, we can load the sample data by clicking [...] > “Load Sample Data.” When data is loaded, we are ready to clone the project stub branch:
git clone -b stub
:mongodb-developer/mongodb-express-rest-api-example.git
Let’s go to the “server” directory of the project and install the needed packages:
cd mongodb-express-rest-api-example/server
npm install
Now, we are ready to connect our Express server to the MongoDB Atlas Cluster.
Connecting to MongoDB Atlas
Once you locate your connection string, create a config.env file in the server directory. There, assign a new ATLAS_URI variable the
value of the connection string. Replace the and the
with your database username and password. Once done, your file should look similar to the one below.
ATLAS_URI=mongodb+srv://:@sandbox.jadwj.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
Next, open server/db/conn.js and add the implementation of the connectToServer function from the snippet below.
const { MongoClient } = require["mongodb"];
const connectionString = process.env.ATLAS_URI;
const client = new MongoClient[connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
}];
let dbConnection;
module.exports = {
connectToServer: function [callback] {
client.connect[function [err, db] {
if [err || !db] {
return callback[err];
}
dbConnection = db.db["sample_airbnb"];
console.log["Successfully connected to MongoDB."];
return callback[];
}];
},
getDb: function [] {
return dbConnection;
},
};
The main object this module exports out is the _db
variable, which will hold the "sample_airbnb
" database-level object. Via this object, we will be able to access any collection within that
database or change its context to another database. In this tutorial, we will use only a single database named “sample_airbnb
.”
Adding REST API CRUD Routes
The main Express.js part in this tutorial is to expose REST API routes to perform Read, Create, Update, and Delete operations for our listing application. This can be extended for more complex application business logic as your use case requires.
The file that will host the routes is --- “server/routes/record.js”. It uses the Express Router feature:
const express = require["express"];
// recordRoutes is an instance of the express router.
// We use it to define our routes.
// The router will be added as a middleware and will take control of requests starting with path /listings.
const recordRoutes = express.Router[];
Read Route
The Read route will be used when the /listings
path on a GET method is called. It will use a collection.find[] to query our listingAndReviews
collection for the first 50 available listings:
// This section will help you get a list of all the documents.
recordRoutes.route["/listings"].get[async function [req, res] {
const dbConnect = dbo.getDb[];
dbConnect
.collection["listingsAndReviews"]
.find[{}].limit[50]
.toArray[function [err, result] {
if [err] {
res.status[400].send["Error fetching listings!"];
} else {
res.json[result];
}
}];
}];
The code sends back the result set as the API response.
Create Route
The Create route will record a “match” swipe in a “matches” collection. The body of this POST method will present a user session_id
and the swiped direction and listing_id
to create a “match” document.
// This section will help you create a new document.
recordRoutes.route["/listings/recordSwipe"].post[function [req, res] {
const dbConnect = dbo.getDb[];
const matchDocument = {
listing_id: req.body.id,
last_modified: new Date[],
session_id: req.body.session_id,
direction: req.body.direction
};
dbConnect
.collection["matches"]
.insertOne[matchDocument, function [err, result] {
if [err] {
res.status[400].send["Error inserting matches!"];
} else {
console.log[`Added a new match with id ${result.insertedId}`];
res.status[204].send[];
}
}];
}];
The save is done via collection.insertOne[] method with the prebuilt “matchDocument.”
You can also use InsertMany to insert multiple documents at once.
Update Route
The Update route updates the “likes” field on a listing object. This is done via a POST method:
// This section will help you update a document by id.
recordRoutes.route["/listings/updateLike"].post[function [req, res] {
const dbConnect = dbo.getDb[];
const listingQuery = { _id: req.body.id };
const updates = {
$inc: {
likes: 1
}
};
dbConnect
.collection["listingsAndReviews"]
.updateOne[listingQuery, updates, function [err, _result] {
if [err] {
res.status[400].send[`Error updating likes on listing with id ${listingQuery.id}!`];
} else {
console.log["1 document updated"];
}
}];
}];
The method will use the collection.updateOne[] method with a $inc on the “like” field to increment the likes.
Delete Route
Whenever a listing is dropped, we can delete it from the database so that it doesn’t appear anymore. This is done via the Delete route.
// This section will help you delete a record.
recordRoutes.route["/listings/delete/:id"].delete[[req, res] => {
const dbConnect = dbo.getDb[];
const listingQuery = { listing_id: req.body.id };
dbConnect
.collection["listingsAndReviews"]
.deleteOne[listingQuery, function [err, _result] {
if [err] {
res.status[400].send[`Error deleting listing with id ${listingQuery.listing_id}!`];
} else {
console.log["1 document deleted"];
}
}];
}];
The route here includes the :id
parameter. This is the id of the listing to
be deleted via collection.deleteOne[].
Now that we have everything in place, we can launch the server:
npm start
[nodemon] starting `node server.js`
Successfully connected to MongoDB.
Server is running on port: 5000
Setting Up the Front End
Our React application consists mainly of the App.js React file and class.
import './App.css';
import TinderCard from 'react-tinder-card'
import axios from 'axios';
import { Component } from 'react';
import { v4 as uuid } from 'uuid';
class App extends Component {
constructor[] {
super[];
this.state = {
data: [],
session_id: uuid[],
liked: false
};
this.handleClick = this.handleClick.bind[this];
this.showDetails = this.showDetails.bind[this];
}
async onSwipe[direction, listingId, sessionId] {
this.setState[{
liked: false
}];
if [direction === "left"] {
await axios.delete[`//localhost:5000/listings/delete/${listingId}`]
} else {
await axios.post["//localhost:5000/listings/recordSwipe", { id: listingId, session_id: sessionId, direction }]
}
}
async handleClick[listingId] {
this.setState[{
liked: !this.state.liked
}];
await axios.post["//localhost:5000/listings/updateLike", { id: listingId }];
}
showDetails[listing] {
alert[`Name: ${listing.name}\n Price : $${listing.price['$numberDecimal']} \n Minimum Nights : ${listing.minimum_nights}\n Beds : ${listing.beds}`];
}
async componentWillMount[] {
const response = await axios.get[`//localhost:5000/listings`];
const json = await response.data;
this.setState[{ data: json }];
}
render[] {
const likeButtonLabel = this.state.liked ? '❤' : 'Like';
return [
LisTinder
Swipe left for drop or right to save...
{this.state.data.map[[listing] =>
this.onSwipe[dir, listing._id]} >
{listing.name}
this.handleClick[listing._id]}>{likeButtonLabel}
this.showDetails[listing]}>See Details
]}
];
}
}
export default App;
We will use some third-party modules, like the “react-tinder-card”, which will allow us to create the swiping tiles and graphics. Those will interact with the application functions to handle events like “onSwipe,” “handleLikeClick,” “showDetails,” and “componentWillMount” [to show the data on page load].
Functions “onSwipe,” “handleLikeClick,” and “componentWillMount” will use the axios library to perform http REST API requests to our Express server. Those, in turn, will perform the needed action on our Atlas cluster.
Now we can start the application in a new terminal [the server process must remain running]:
cd ../app/listings
npm install
npm start
Testing the Application
Once all components are up and running, we can open the //localhost:3000 URL and we should see our “LisTinder” application loaded:
Interaction with the tiles by swapping them will call our Express routes and perform application operations.
Successfully connected to MongoDB.
1 document updated
1 document deleted
Atlas App Services Webhooks as Express Replacement
Atlas App Services, MongoDB’s mobile database and development cloud services, offer a robust and scalable replacement to the self-hosted Express Server.
Creating an application is very easy with a generous free tier. In that application, you can create HTTP services with webhook endpoints to perform the same operations as the Express routes, without the need for maintaining and coding lots of boilerplate code. Those services are optimised for Atlas cluster access and will open a new world of opportunities like cloud functions, auth providers, GraphQL, and triggers.
Let’s port one route to a webhook. We will start by creating an HTTP service within a newly created Realm application UI.
Create HTTP Service
Navigate to the “3d Party Services” section and click on the HTTP service type.
Create Webhook for That Service
As part of defining the service, we need to configure the HTTP method this webhook will use and its associated function logic.
The associated function code:
// This function is the webhook's request handler.
exports = async function[payload, response] {
// Querying a mongodb service:
return await context.services.get["mongodb-atlas"].db["sample_airbnb"].collection["listingsAndReviews"].find[{}].limit[50];
};
Now we can use the webhook URL directly in the React application. Add the following to the app class in App.js:
async componentWillMount[] {
const response = await axios.get[``];
const json = await response.data;
this.setState[{ data: json }];
}
Wow, that's much easier and more scalable!
Summary
Using Express as a back-end middleware is a popular MongoDB stack design. Express is lightweight and approachable for JSON and REST API operations. MongoDB Atlas is a scalable and flexible document Database-as-a-Service and makes a perfect companion to Express in many stacks like MERN, MEAN, and MEVN.
Having said that, Atlas App Services and webhooks are a robust replacement for the Express tier, moving the need to manage an Express server and its dependencies on-prem.