A beginner’s guide to writing an API

APIs (Application Programming Interface) are building blocks of most of today’s web. APIs allow one service to talk to another, one site to embed content from another, and power virtually everything online.

As a website or web app creator, you might be wondering if you should provide an API for the service you provide. If your functionality could be useful to others in their sites or apps, then the answer is yes. For example, WhoAPI provides advanced domain and website APIs, making it possible for other apps or sites to make use of it directly. Another typical example is Google Maps API, in which others embed maps directly into their sites, with varying levels of customizations.

Choosing the tech stack

Once you decide to build an API, the first question is what technology you want to use. If you’re already using a web framework for your main site and you’re just adding an API to it, the choice is clear – you continue to use your preferred tech stack. On the other hand, if you’re building an API as a stand-alone product, it makes sense to choose a platform that will make building APIs easy.

The choice also depends on the developer knowledge your team has. If you have (or are) a NodeJS developer, you could either go with Express, a gold standard for Node web servers, or Fastify, a newer framework optimized specifically for APIs. Python developers will most likely want to choose Django REST Framework or FastAPI, and PHP devs have Lumen (from the team behind Laravel) and many others.

In this article, we’ll use NodeJS, the web application platform with the largest community, and Express, the framework most Node devs are at least familiar with. We’re going to build “Example API”, a simple project which still includes everything you need to set up for your API.

Setting up Express

The first step in building an API project is to set up our development environment. First, you’ll need to download and install Node if you haven’t already. Following that, you should have node and npm command available in your shell.

Next, we’ll set up a new Git repository for our new project, and set up the project configuration file:

  git init example-api
  cd example-api/
  npm init

The npm init command will ask you a bunch of questions and create the configuration file package.json. All the questions have reasonable default answers so you can just hit Enter to go through the process.

After that, we can install Express and a few other Node packages we’ll need:

npm install --save express cors

Finally, create the index.js file in the same directory with the following contents:

const express = require('express')
const cors = require('cors')
const app = express()

app.use(cors())
app.use(express.json())

app.get('/', function (req, res) {
  res.send('Hello World')
})

app.listen(3000)

Time to try it out! Run your new server:
node index

Point your browser to http://localhost:3000/ and you should see “Hello world!”

Your first API

Okay, we got a web server. Now we need to add some APIs for it, and for that, we need to first think about what exactly do we want our (developer) users to be able to do.

Broadly speaking, there are three kinds of APIs, and your service will likely have a few of each kind:

  • APIs that just get something from the server. For example, WhoAPI has a domain whois API that returns whois info for the domain you ask it for.
  • APIs that ask the server to do something and return the result. An example is the WhoAPI screenshot API that takes a screenshot of the website you point it at and returns the image.
  • APIs that allow you to create, modify and update data that’s on the server, usually called CRUD (Create/Read/Update/Delete) APIs. These expose, in a controlled fashion, access to the server database.

In our example, we’ll cover the first two kinds and just briefly touch on the CRUD APIs and give you pointers for more information.

Now, let’s build our API. First, we’ll create an “API endpoint” that returns the current date and time. By the way, “API endpoint” is just like a web page, except for APIs. It has an address, you can send data to it and get a response back.

Open the index.js file we created previously and add this before the final app.listen line:

app.get('/now', function (req, res) {
  res.send({
    now: new Date()
  })
})

Save the changes and run your server again with node index, as previously. Then point your browser to http://localhost:3000/now and you should see a JSON API response with the current date and time.

Ok, time to hit the breaks and explain the multiple things that are important here:

First, we’re doing what’s called a GET request. These are the “normal” requests your browsers use all the time when you browse the web. A GET request just says to the server “give me whatever is on this URL address”. But, instead of the usual HTML web page, our server responds with a JSON response. JSON is a standard way to transmit structured data (think strings, lists of strings, and key:value objects) from server to client, and is supported by virtually every client and server on the planet. Since we enabled JSON support (that was the app.use(express.json()) line we added previously), Express knows we’re implementing an API and uses JSON automatically.

Testing APIs

While it was easy for us to test this simple endpoint, for more complex APIs it’s better to use a specialized client, such as Postman, Insomnia, Paw (Mac-only), or a command-line tool such as curl. Even if you use a GUI client, it is helpful to know at least the basics of curl and it is easy to use in text-based tutorials such as this one.

To test the current-time-and-date endpoint with curl, you’d use something like this:

curl http://localhost:3000/now

You’ll get a response such as this:
{"now":"2022-02-07T09:57:30.818Z"}

This doesn’t show request and response details, such as response code or headers. To show these as well, add -v (verbose) flag to curl:

curl -v http://localhost:3000/now

POST APIs and content types

APIs which ask the server to do something heavy-duty for us, for example, process some data we send, usually use the POST request type. This is the same request type that is used when you submit a contact form on a site or upload your profile image on Facebook, but in this case, we’re going to use it for API purposes.

Sending something to the server complicates things as we need to tell the server in what format we’re sending the data. We’ve already encountered JSON and we can use it to send data (also called “request payload”), but there are others. We tell the server how we’re sending the data by setting up a request header called Content-Type to a specific value – in this case, application/json.

Headers are additional meta-data attached to every web request and response. In normal web browsing, your browser usually responds with HTML pages using text/html content-type. In our GET API example, Express automatically set the Content-Type header on the response to application/json (check with curl -v if you’re curious).

Ok, enough with the theory. Let’s add another API endpoint. This one will take two numbers, add them together and return the result. Open index.js and add the following before the last app.listen line:

app.post('/add', function (req, res) {
  const first = req.body.first
  const second = req.body.second

  res.send({
    result: first + second
  })
})

Notice we now use app.post to tell Express we want to handle the POST request. We pull the numbers from the request body – Express will automatically parse the request JSON and set up the data for us. Then we do our work and send the result back.

Let’s test this with curl:

curl -H "Content-type: application/json" -d '{"first": 1, "second": 2}' http://localhost:3000/add

Quite a mouthful! We had to specify the request content type (that’s the -H option’) and send the data in raw JSON format (that’s the -d option). Now the GUI clients for APIs come in handy, as you don’t want to type this manually each time you make an API request. On the other hand, using a plain browser without any specialized tools and without JavaScript, would be very hard to test.

Browser-friendly APIs

If you want your API to be easily used from a web page without coding JavaScript, you’re probably going to be using GET requests and passing request options via “query params” (that’s the part of the URL address after the ? sign).

For example, here’s how WhoAPI request for whois looks like:

https://api.whoapi.com/?domain=whoapi.com&r=whois&apikey=YOUR_API_KEY

The domain=whoapi.com&r=whois&apikey=YOUR_API_KEY part (after the ? sign) is called a query, and the parameters are written as key=value pairs separated by the & sign. There are some special rules on what to do if any value contains those special characters, but most programming languages have built-in functions to prepare this (often called urlencode or quote).

This type of request is simpler than POST with the body if you need to pass just a few options, and works nicely with GET. But when you get to more complicated requests with several parameters, or passing complex parameters such as lists of objects, it’s better to use POST.

CRUD APIs

So far we haven’t mentioned databases. What if you have data you want your users to access or modify? Usually in this case, you’d build something called a CRUD API. CRUD stands for Create, Read, Update and Delete, which are basic operations you’d do on an object in a database.

On the most basic level, your API would expose:

  • GET – list all objects in the database, for example at the URL path /records/
  • POST – create a new object in the database, for example at the URL path /records/ or /records/
  • GET – get details of a single object, for example at /records/RECORD-ID
  • PUT – update the object in the database, also at /records/RECORD-ID
  • DELETE – to delete the object also at /records/RECORD-ID

Many new things here! First, there are other request types besides GET and POST. PUT is almost like POST but is better practice to use for objects which you just upload and save, and DELETE is usually used for operations that remove data. Note that none of these are automatically created for you – this is just a way to organize your API to make it easy for your API users.

Also notice that multiple different request types can use the same URL! The URL path is considered an “address” of a “resource” (object in the database), and the request operation (or method) describes what to do on that object.

Next steps

This beginner tutorial just describes the first steps you need to take to start building your API. There are many things we’ve left out, such as:

  • Authentication and authorization – limiting who can access your API
  • Database – handling your data and information about your users
  • Rate limiting – putting “breaks” on your API so users can’t make too many requests in a short time, overwhelming your server
  • Input validation – validating data your server gets from requests, checking the proper format and accepted values
  • Error handling – making sure any errors in either input data or your operation are nicely reported to the users
  • Documentation – your users aren’t mind-readers and will need help in figuring out how your API should be used

As you’ve seen, while it is straightforward to start building your APIs, there are a number of steps you need to do. Instead of starting from scratch, you could also use one of the code generators that create the server for you, such as API Bakery. API Bakery eliminates the setup step, helps you create a database customized to your needs, and produces code that follows best practices in structure, input validation, and error handling. You also get automated tests and documentation which lets your users experiment with your API directly from their browser.

Especially if this is your first API, tools such as API Bakery are useful because it gives you a good structure and information of “how things are done” when you want to set up an API server. More than just saving you a few days of work, it’ll help you learn faster and learn better. API Bakery is free so definitely give it a try.

Post a Comment