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.
Fork
this repository.Clone
yourfork
.
In this step, we will create a package.json to keep track of our server's dependencies.
- Run
npm init -y
In 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
.gitignore
file in the root of the project. - Add
node_modules
on 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.js
file inserver/
. - Open
server/index.js
. - Require
express
in a variable calledexpress
. - Create a variable called
app
that equals the invocation of theexpress
package. - Call the
use
method on app and pass in theexpress.json
method invoked. - Call the
listen
method on app. The app should listen on port 3001:- The first parameter of
listen
is the port number. - The second parameter of
listen
is 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
books
that equals an empty array.- The
books
variable will keep track of all our books. A book will be an object that has anid
,title
, andauthor
property.
- The
- Create a variable called
id
that equals0
.- After a creation of a book, we will increment this by
1
to insure no books have the sameid
.
- After a creation of a book, we will increment this by
- Use
module.exports
to export an object. - Open
server/index.js
. - Require the books controller at the top of
server/index.js
in 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
get
endpoint.- 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
read
in themodule.exports
object.- This method should return all the books.
- Return to the
get
endpoint inserver/index.js
that we just wrote and add theread
method 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
get
endpoint, add apost
endpoint.- 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
create
in themodule.exports
object.- This method should add a new book from the request body to the
books
array. - When finished, it should return all the books.
- Keep in mind, the information you'll be getting from the request body are
title
andauthor
. You'll have to add your own id property with the value coming from theid
variable. Don't forget to increment theid
variable when you're done.
- This method should add a new book from the request body to the
- Return to the
post
endpoint inserver/index.js
that we just wrote and add thecreate
method 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
post
endpoint, add aput
endpoint.- You will be using the
params
object 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
update
in themodule.exports
object.- This method should find a specific book based off of an id that you'll get
off of the
params
object. - 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
put
endpoint inserver/index.js
that we just wrote and add theupdate
method 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
put
endpoint, add adelete
endpoint.- You will be using the
params
object 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
delete
in themodule.exports
object.- This method should find a specific book based off of an id that you'll get
off of the
params
object. - Once the book is found, remove that book from the
books
array. - 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
delete
endpoint inserver/index.js
that we just wrote and add thedelete
method 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
use
method on app and pass inexpress.static( __dirname + '/../build')
. - Add some books to your collection using Postman.
- Open up
http://localhost:3001
in 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
update
one of the books, rember to use anid
. - Use insomnia to
delete
one of the books.
Congratulations you just created a full CRUD API from scratch.