This guide is focused around preparing for a React based stack. React relies heavily on a single-page application (SPA) design pattern, so having a functional API is essential to this, given the additional reliance on asynchronous operations. The guide assumes basic familiarity with HTTP requests, RESTful routing, and Express.js apps.
This guide will help you build a JSON API. Then, you can use this API to build an AJAX SPA (not included).
We can mix and match different technologies to accomplish our goal. For the sake of this guide, I will be using React and Express.js to create a SPA with an API. However, there are alternatives:
We can use a few different tools on the front end:
- Vanilla JS
- jQuery
- React
- Angular
We can also use a few different tools on the back end:
- Express.js
- Rails
- Django
- Flask
In this example we are creating an interactive Todo List. We need to relay the following data:
| Field | Type |
|---|---|
| name | String |
| isCompleted | Boolean |
| dateCreated | Date |
We need to create the following routes:
| Verb | Route | Description |
|---|---|---|
| GET | /api/todos | List all todos |
| POST | /api/todos | Create new todo |
| GET | /api/todos/:todoId | Retrieve a todo |
| PUT | /api/todos/:todoId | Update a todo |
| DELETE | /api/todos/:todoId | Delete a todo |
We can create simple routes that return more than just a page or text:
const express = require("express");
const app = express()
app.get("/", (req, res) => {
res.send({
message: "Hello from a JSON!"
});
});
app.get("*", (req, res) => {
res.redirect("/");
});Despite our call to res.send(), Express identifies that we are only passing a JSON, and instead uses res.json(). The developer may use either and it will yield the same result:
res.send({
message: "Hello from a JSON!"
});
// is the same as:
res.json({
message: "Hello from a JSON!"
});First, we need to create a schema and model for our Todo items:
const mongoose = require("mongoose");
const todoSchema = new mongoose.Schema({
name: {
type: String,
required: "Item must have a name."
},
isComplete: {
type: Boolean,
default: false
},
dateCreated: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model("Todo", todoSchema);Leveraging body-parser, the Todo model we created, and Promises, we can create helper functions that perform all the requests we require. MongoDB gives us JSON objects anyway so, unlike more typical routes, we skip the post-processing step.
Note: Please refer to the reference project linked at the beginning of the guide for the full code. This has been distilled down into the essentials.
var db = require("../models");
exports.getTodos = (req, res) => {
/// Gets all Todo items
db.Todo.find().then((data) => {
console.log(data);
res.json(data)
}).catch((err) => {
res.send(err);
});
}
exports.createTodo = (req, res) => {
db.Todo.create(req.body).then((data) => {
console.log(data);
res.json(data);
})
.catch( (err) => {
res.send(err);
});
}
exports.getTodo = (req, res) => {
/// Gets a specific Todo
db.Todo.findById({_id: req.params.id}).then((data) => {
console.log(data);
res.json(data);
}).catch((err) => {
res.send(err);
});
}
exports.updateTodo = (req, res) => {
// Note: The request body contains our update info.
db.Todo.findOneAndUpdate({_id: req.params.id}, req.body).then((data) => {
res.json(data);
}).catch((err) => {
res.send(err);
});
}
exports.deleteTodo = (req, res) => {
db.Todo.findByIdAndRemove({_id: req.params.id}).then((data) => {
console.log(`Deleted ${data}`);
res.json(data);
})
.catch((err) => {
res.send(err);
});
}These are, in turn, used by our routes:
const express = require("express");
const router = express.Router();
const db = require("../models");
const todoHelper = require("../helpers/todos");
// /api/todos
router.route("/")
.get(todoHelper.getTodos)
.post(todoHelper.createTodo)
// /api/todos/:id
router.route("/:id")
.get(todoHelper.getTodo)
.put(todoHelper.updateTodo)
.delete(todoHelper.deleteTodo)
module.exports = router;It is now up to the developer to interact with our API and determine the best way to present information for their own site. APIs offer unparalleled flexibility; we are no longer bound to serving information on a particular page in a specific way. APIs may even serve similar information to similar users, but each user may have their own customized experience.