In this project, we will create a node server that will act as a bookshelf. This server will keep track of books by being able to add books to a collection, read from the collection, update the collection, and delete from the collection. We'll use insomnia to test our endpoints.
Forkthis repository.Cloneyourfork.
In this step, we will create a package.json to keep track of our server's dependencies.
- Run
npm init -yIn this step, we will install express, which is a very common package node
developers use when making a node server.
- Run
npm install --save express
In this step, we will create a .gitignore file to ignore the node_modules
folder npm install created.
- Create a
.gitignorefile in the root of the project. - Add
node_moduleson the first line and save the file.
.gitignore
node_modules
In this step, we will create our server and have it listen on port 3001.
- In the root of the directory create a folder called
server. - Create an
index.jsfile inserver/. - Open
server/index.js. - Require
expressin a variable calledexpress. - Create a variable called
appthat equals the invocation of theexpresspackage. - Call the
usemethod on app and pass in theexpress.jsonmethod invoked. - Call the
listenmethod on app. The app should listen on port 3001:- The first parameter of
listenis the port number. - The second parameter of
listenis a callback function that is called when the app starts listening.
- The first parameter of
server/index.js
const express = require('express');
const app = express();
app.use(express.json());
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will create a controller that keeps track of the book
collection and import that controller into server/index.js. You can think of a
controller as an interface to the underlying data we are interested in
accessing.
- Create a folder in
server/calledcontrollers. - In
server/controllers/create a file calledbooksController.js. - Open
server/controllers/booksController.js. - Create a variable called
booksthat equals an empty array.- The
booksvariable will keep track of all our books. A book will be an object that has anid,title, andauthorproperty.
- The
- Create a variable called
idthat equals0.- After a creation of a book, we will increment this by
1to insure no books have the sameid.
- After a creation of a book, we will increment this by
- Use
module.exportsto export an object. - Open
server/index.js. - Require the books controller at the top of
server/index.jsin a variable calledbc.
server/controller/booksController.js
let books = [];
let id = 0;
module.exports = {}; server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will create the endpoint to get all the books. We will also
create the method in the booksController to be used as the endpoint's handler
function.
When creating a get route, you can use the get method on the app object.
The first argument is the URL of the request and the second argument is the
function to execute when that URL is hit. We will be getting that function from
the booksController.
- Open
server/index.js. - Below the top level middleware and above the listen method invocation, add a
getendpoint.- The URL path should be
/api/books. - The handler function will come from the
booksController, we will add it once we create it.
- The URL path should be
- Open
server/controllers/booksController.js. - Create a method called
readin themodule.exportsobject.- This method should return all the books.
- Return to the
getendpoint inserver/index.jsthat we just wrote and add thereadmethod as the second argument after the URL path.
server/controller/booksController.js
let books = [];
let id = 0;
module.exports = {
read: (req, res) => {
res.status(200).send(books);
},
}; server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
app.get('/api/books', bc.read);
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will create the endpoint to post a new book. We will also
create the method in the booksController to be used as the endpoint's handler
function.
- Open
server/index.js. - Below the
getendpoint, add apostendpoint.- The URL path should be
/api/books. - The handler function will come from the
booksController, we will add it once we create it.
- The URL path should be
- Open
server/controllers/booksController.js. - Create a method called
createin themodule.exportsobject.- This method should add a new book from the request body to the
booksarray. - When finished, it should return all the books.
- Keep in mind, the information you'll be getting from the request body are
titleandauthor. You'll have to add your own id property with the value coming from theidvariable. Don't forget to increment theidvariable when you're done.
- This method should add a new book from the request body to the
- Return to the
postendpoint inserver/index.jsthat we just wrote and add thecreatemethod as the second argument after the URL path.
server/controller/booksController.js
let books = [];
let id = 0;
module.exports = {
read: (req, res) => {
res.status(200).send(books);
},
create: (req, res) => {
const { title, author } = req.body;
let book = {
id,
title,
author,
};
books.push(book);
id++;
res.status(200).send(books);
},
}; server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
app.get('/api/books', bc.read);
app.post('/api/books', bc.create);
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will create a put endpoint to update a specific book by it's
id. We will also create the method in the booksController to be used as the
endpoint's handler function.
- Open
server/index.js. - Below the
postendpoint, add aputendpoint.- You will be using the
paramsobject in this endpoint, specifically an id you'll get from the URL parameters. Make sure to indicate this at the end of the URL path/api/books. - The handler function will come from the
booksController, we will add it once we create it.
- You will be using the
- Open
server/controllers/booksController.js. - Create a method called
updatein themodule.exportsobject.- This method should find a specific book based off of an id that you'll get
off of the
paramsobject. - Once the book is found, update the book with the new information you'll get off of the request body.
- Return all the books.
- This method should find a specific book based off of an id that you'll get
off of the
- Return to the
putendpoint inserver/index.jsthat we just wrote and add theupdatemethod as the second argument after the URL path.
server/controller/booksController.js
let books = [];
let id = 0;
module.exports = {
read: (req, res) => {
res.status(200).send(books);
},
create: (req, res) => {
const { title, author } = req.body;
let book = {
id,
title,
author,
};
books.push(book);
id++;
res.status(200).send(books);
},
update: (req, res) => {
const bookToUpdate = books.find(book => Number(req.params.id) === book.id);
if (bookToUpdate) {
const { title, author } = req.body;
Object.assign(bookToUpdate, {
...(title && { title }), // conditionally applies if title is defined
...(author && { author }), // conditionally applies if author is defined
});
return res.status(200).send(books);
}
return res.status(404).send({ error: 'Could not find specified book.' });
},
}; server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
app.get('/api/books', bc.read);
app.post('/api/books', bc.create);
app.put('/api/books/:id', bc.update);
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will create a delete endpoint to delete a specific book by
it's id. We will also create the method in the booksController to be used as
the endpoint's handler function.
- Open
server/index.js. - Below the
putendpoint, add adeleteendpoint.- You will be using the
paramsobject in this endpoint, specifically an id you'll get from the URL parameters. Make sure to indicate this at the end of the URL path/api/books. - The handler function will come from the
booksController, we will add it once we create it.
- You will be using the
- Open
server/controllers/booksController.js. - Create a method called
deletein themodule.exportsobject.- This method should find a specific book based off of an id that you'll get
off of the
paramsobject. - Once the book is found, remove that book from the
booksarray. - Return all the books.
- This method should find a specific book based off of an id that you'll get
off of the
- Return to the
deleteendpoint inserver/index.jsthat we just wrote and add thedeletemethod as the second argument after the URL path.
server/controller/booksController.js
let books = [];
let id = 0;
module.exports = {
read: (req, res) => {
res.status(200).send(books);
},
create: (req, res) => {
const { title, author } = req.body;
let book = {
id: id,
title: title,
author: author,
};
books.push(book);
id++;
res.status(200).send(books);
},
update: (req, res) => {
const bookToUpdate = books.find(book => Number(req.params.id) === book.id);
if (bookToUpdate) {
const { title, author } = req.body;
Object.assign(bookToUpdate, {
...(title && { title }), // conditionally applies if title is defined
...(author && { author }), // conditionally applies if author is defined
});
return res.status(200).send(books);
}
return res.status(404).send({ error: 'Could not find specified book.' });
},
delete: (req, res) => {
const bookIndex = books.findIndex(
book => Number(req.params.id) === book.id
);
if (bookId > -1) {
books.splice(bookIndex, 1);
return res.status(200).send(books);
}
return res.status(404).send({ error: 'Could not find specified book.' });
},
}; server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
app.get('/api/books', bc.read);
app.post('/api/books', bc.create);
app.put('/api/books/:id', bc.update);
app.delete('/api/books/:id', bc.delete);
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});In this step, we will use express.static to serve the index.html file for
the web application that utilizes our API. express.static takes an argument
that is the location of the folder with the files you want to serve when the
server URL is hit in a browser. Our front-end was made using create-react-app
and instead of running it's own server, we have made a production ready build so
that our server can serve up our frontend. We'll want to serve the entire
build folder.
- Call the
usemethod on app and pass inexpress.static( __dirname + '/../build'). - Add some books to your collection using Postman.
- Open up
http://localhost:3001in your browser. - You should see the react application being served from our express server
server/index.js
const express = require('express');
const bc = require('./controllers/booksController.js');
const app = express();
app.use(express.json());
app.use(express.static(__dirname + '/../build'));
app.get('/api/books', bc.read);
app.post('/api/books', bc.create);
app.put('/api/books/:id', bc.update);
app.delete('/api/books/:id', bc.delete);
const port = 3001;
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});We'll add some data to our API server using insomnia.
- Add some books utilizing the React application. If it's not working look back at your server implementation.
- Use insomnia to
updateone of the books, rember to use anid. - Use insomnia to
deleteone of the books.
Congratulations you just created a full CRUD API from scratch.