Creating a REST API in node.js
Getting started with making web APIs can be confusing, even overwhelming at first. I'd like to share my process for creating APIs in Node.js.
The server
First let's create a package.json
and add a dependency:
This is a simple 'hello world' with express:
Express is imported, then an instance is created and saved as app
.
app.get()
tells the Express instance to listen for GET
requests to the specified route; here it's just /
. When this route is requested, the given callback is fired, in this case it sends the string "Hello world!" as a response.
port
is declared as a variable which can be set from the environment, or otherwise defaults to 3000
if none is specified. Express then listens on that port, and after the server has finally started it uses console.log
to print a message in the terminal.
This is a simple 'hello world' with express:
Express is imported, then an instance is created and saved as app
.
app.get()
tells the Express instance to listen for GET
requests to the specified route; here it's just /
. When this route is requested, the given callback is fired, in this case it sends the string "Hello world!" as a response.
port
is declared as a variable which can be set from the environment, or otherwise defaults to 3000
if none is specified. Express then listens on that port, and after the server has finally started it uses console.log
to print a message in the terminal.
Assuming everything went okay, you should then be able to run node index.js
and point your browser at http://localhost:3000/ and see the message "Hello world!"
Another way to test this instead of opening your browser is with either cURL or postman. cURL is great if you're the command-line junkie type (like me), postman is really pretty and slick but a bit too much hassle for me.
Once you have curl installed it should be as simple to get your Hello World in the shell with:
Request parameters
A server that only responds with the same thing every time isn't very fun though. Let's make a new route that allows us to say hello when passed a name:
You'll want to add this before the app.listen()
command so that it gets registered properly.
Then, with curl:
You should see "Hello foo!"
Automatic restart
To get the above change working, you first have to stop the server and then restart it again, which can get fairly annoying after a few changes. nodemon can be installed to watch for changes and restart automatically.
Then alter your package.json so that it looks like this:
Now you can run npm start
and it will use nodemon to watch for changes and restart the server.
The database
Before making a database, you should first identify your data and what you'll be doing with it. I spent about 30 seconds debating what kind of data to use in this tutorial, and decided to do "something" with movies.
Among other things, a movie would have a title and a date it was released, and that seems like enough to work with for now.
I don't want to go into setting up and configuring a big fancy database, so we will SQLite, a RDBMS that uses files to represent databases, and doesn't require a background processes to store or retrieve data. If you prefer PostgreSQL or MariaDB feel free to use those, you should only have to adjust a couple of things.
Rather than interacting with the database directly, we're going to use a query builder called knex. knex allows you to write your queries in plain JavaScript, which provides an abstraction layer over your database driver. This makes it so your queries aren't necessarily tied to a specific database engine, and if you want to change to a different database later it's a much less difficult migration, sometimes only just a few lines.
knex
has a really great cli. We can use it to create a default config:
Have a look at the file it creates at knexfile.js
In a new file, perhaps called db.js
, save this:
This creates and exports a single knex instance that we can re-use in other modules.
Now let's define a new table using the migrations cli:
This will create migrations/<timestamp>_create_movies.js
with a few empty functions, change it so that it looks like this:
Now, we can use the cli again to create our table:
Data methods
Now that we have a database and a table, we need some methods to populate the table with data.
This creates a function called create
that accepts an object with keys title
and released
, which are purposely the same name as the field names.
Now that we can create movies, we should make a way to list them.
To finish up, since this file won't directly consume these functions, we need to export them so they can be used as a module.
This creates a function called create
that accepts an object with keys title
and released
, which are purposely the same name as the field names.
Now that we can create movies, we should make a way to list them.
To finish up, since this file won't directly consume these functions, we need to export them so they can be used as a module.
Wiring it up
Now let's wire up our database to our server!
Going back to our index.js
, let's import our new movies file and make a route to use the list
method so that it looks like this:
Requesting the data is the easy part, with curl we can simply:
which right now will return an empty JSON array.
Express middleware
To be able to properly create movies, we need to introduce a piece of express middleware.
Middleware are functions that are run before a route handler. They usually alter the request or response objects in some way. There are tons of middleware modules for express, if you'd like to read more you can check out the offical docs.
Now we can add a route that responds to POST
requests, and our body data will be available as req.body
:
Using curl we can now insert data with:
Which will return the new number of rows.
Full CRUD support
Any good API endpoint usually provides four methods:
- Create
- Read
- Update
- Delete
We only have the first two, so let's finish it up and add the others.
Back in our movies.js
let's add two more functions:
Then we need to update our exports:
Back in the index.js
file we need to make two more routes:
Now we can edit movies by passing field names as data pieces in curl:
And delete them by passing the id:
Conclusion
We learned how to make a single endpoint respond to different actions and query a database with the appropriate methods.