In this article, you will learn to write a simple RESTful API using Node.js
and Express
.
This article will be useful if you are familiar with these concepts:
- ES6 syntax: arrow function, object notation, string templates.
- callbacks.
- JSON format.
What we'll cover:
- Setting up the project.
- Adding express.
- Running the server.
- Introducing middlewares.
- jq
This article does not cover the design of RESTful APIs. We'll cover that in another article. The aim of this article is to introduce you to the Express web framework and show you how great is for creating RESTful APIs. I use it often when I have to provide testing APIs for client's integrations or when I'm developing full stack project and the front client needs to consume an API.
All sorts of microservices can be made with Node.js
and Express
, within a few minutes you can have a nice and small server listening for requests. In this article, I’ll go through the whole process of setting up the project and running the server for the first time.
Setting up the project
Let’s start by creating the project.
$ mkdir micro-server
$ cd micro-server
$ npm init -y
As you can see npm init
creates a package.json
, this is the configuration file for our project. It contains scripts and dependencies. The -y
option tells npm
to autocomplete the questions that otherwise would ask you. Let's add some elements to our package.json
file, open your favourite editor and add the author
, the description
and a start
script.
{
"name": "temp",
"version": "1.0.0",
"description": "A hello world example",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node ."
},
"keywords": [],
"author": "S.Espinoza",
"license": "ISC"
}
Adding Express.
To add express
to the dependencies is straight forward by running npm install express --save
. This will create and install express
inside a node_modules
folder and the --save
option will save the stable version of Express
to our dependencies in the package.json
. With express
added, we now proceed to create an index.js
file and start using express.
$ touch index.js
Open your editor and put this in your file.
const express = require('express')
const app = express()
app.get('/user/:name', (req, res) => {
return res.status(200).json({
msg: `Hi ${req.params.name}`
})
})
app.all('*', (req, res) => {
return res.status(404).json({
msg: 'These are not the droids you are looking for'
})
})
app.listen(4000, () => console.log('listening in on 4000'))
In general, every method in express
receives as arguments a path and a callback, except listen
which receives the port to listen as the first argument. Once the request matches one of the methods, it executes its callback.
An instance of express (app
) has may methods, with different arguments. Here are some of the most important.
method | arguments | Description |
---|---|---|
get |
(path, callback) | match GET request |
post |
(path, callback) | match POST request |
put |
(path, callback) | match PUT request |
delete |
(path, callback) | match DELETE request |
all |
(path, callback) | match all request |
listen |
(port, callback) | start the server in port and then executes a callback |
In our example
-
app.listen
start the server to listen to requests on port4000
. -
app.get
match requests tolocalhost:4000/user/:name
. -
app.all
match everything that doesn't match all the previews methods.
Yes, the order in which you write you matches matter, they should be structured top to bottom according to it's relevance.
The callback
In our callback for the main methods, excluding listen
, the first parameter is the path which in our case is /user/:name
and the second parameter is the callback that receives two arguments:
- the
request
objectreq
holds all the data that the user sends in this case, theparams
. - the
response
objectres
formats the response to be sent to the user.
Running the server.
Let's run the server now. For that we could type node index.js
or node .
but as we added a start script in our package.json
we can run our server with npm start
. The message listening in on 4000
should appear if everything went well.
$ npm start
> micro-server@1.0.0 start /home/sam/micro-server
> node .
listening in on 4000
And now we can test it using curl
.
$ curl localhost:4000/user/Alexander
{"msg":"Hi Alexander"}
Great! we are up and running. If we forgot to the add the param or if we try to place any other path we would get Owi One's words:
$ curl localhost:4000/this/path/does/not/exist
{"msg":"These are not the droids you are looking for"}
Introducing middlewares.
Understanding middlewares
A middleware is a piece of code that executes sequentially before hitting the last callback to respond to the user, this is useful, for example, to parse the content in the request object or for authentication proposes. Here we'll make a little example in our code and then we'll add some useful Third-party libraries to use as middlewares.
A middleware is a function with the following structure:
(req, res, next) => {
/* do something*/
next()
}
Once a middleware finish whatever it does, it should always call the next()
function so that the next middleware is called. You can have multiple middlewares that performs different tasks.
app.get('/', (req, res, next) => { /* do something*/ next() },
(req, res, next) => { /* do something*/ next() },
(req, res) => res.status(200).json({}))
For our example we'll use something very simple: put the greeting message in the request object.
const formatGreetings = (req, res, next) => {
req.greetings = `Hi ${req.params.name}, coffee?`
next()
}
app.get('/user/:name', formatGreetings, (req, res) => {
return res.status(200).json({ msg: req.greetings })
})
app.all('*', (req, res) => {
return res.status(404).json({
msg: 'These are not the droids you are looking for'
})
})
app.listen(4000, () => console.log('listening in on 4000'))
If we test it again
$ curl localhost:4000/user/Alexander
{"msg":"Hi Alexander, coffee?"}
Excellent!
Third-party libraries
Our example as it is wont handle Cross-Origin Resource Sharing (CORS) nor will format well the body of POST requests. So we need to add two more libraries to our dependencies: cors
and body-parser
.
$ npm install cors body-parser --save
Let's add a new POST match just before our GET.
const express = require('express')
const app = express()
const bparser = require('body-parser')
const cors = require('cors')
app.use(cors())
app.use(bparser.json({ type: 'application/json' })) // parse JSON
app.use(bparser.urlencoded({ extended: true })) // parse URL-encoded
const formatGreetings = (req, res, next) => {
req.greetings = `Hi ${req.params.name}, coffee?`
next()
}
app.post('/', (req, res) => {
return res.status(200).json({
msg: `creating user ${req.body.name}`
})
})
app.get('/user/:name', formatGreetings, (req, res) => {
return res.status(200).json({
msg: `Hi ${req.params.name}`
})
})
app.all('*', (req, res) => {
return res.status(404).json({
msg: 'These are not the droids you are looking for'
})
})
app.listen(4000, () => console.log('listening in on 4000'))
Now if we test it.
$ curl -s -XPOST -H 'Content-type: application/json' \
-d '{ "name": "sam" }' \
localhost:4000/
{"msg":"creating user sam"}
Perfect. The app.use()
call tells express to use a top-level middleware before every request. In this case to parse JSON and URL-encoded.
The urlencoded
option in the body-parser
just tells the middleware how to parse the body. Here I quote from the docs.
A new body object containing the parsed data is populated on the request object after the middleware (i.e. req.body). This object will contain key-value pairs, where the value can be a string or array (when extended is false), or any type (when extended is true).
jq
If you are like me and you always consume APIs in the terminal, one of the best tools I've found is jq
. It's an excellent parser and if you have a huge JSON object it's very useful. Here is an example.
$ curl -s localhost:4000/Alexander | jq .
{
"msg": "Hi Alexander"
}
$ curl -s localhost:4000/Alexander | jq .msg
"Hi Alexander"
That's it for this article, I really hope this was useful for you, if you think there's a mistake in this article or if there's room to improve it let me know in the comments.
If you want me to talk about a specific topic just leave a comment or contact me through my page.
References
Originally posted in:
About me
I’m a Software Engineer, writer, tech enthusiast, pianist, origami lover, amateur photographer. In my spare time, I go trekking, play the piano and learn history.
My tech: JavaScript, Node.js, React, Ruby, Crystal, Bash, Docker.
You can follow me on Twitter, LinkedIn or visit my page to contact me.
Top comments (0)