Link Search Menu Expand Document

Intro to Express.js

Express.js is a web framework for Node.js server-side applications. Here’s a Hello World Express app.

const express = require("express")
const app = express()
const port = 3000

// When the path "/" is visited, send a page that says "Hello World!".
app.get("/", (req, res) => {
  res.send("Hello World!")
})

// Run the app.
app.listen(port, () => {
  console.log(`API listening at http://localhost:${port}`)
})

Visiting http://localhost:3000/ would present a page like this:

Hello World!

Some Definitions

  • Backend Development: Has to do with working on server-side software, including databases, backend logic, application programming interfaces, architecture, and servers.
  • Database: A file or service that stores data for an application.
  • API: Application Programming Interface: A set of procedures enabling access to functionality and data.
    • REST API: A RESTful API allows for client-server communication over HTTP, where resources are accessed via endpoints.
  • Endpoints (URIs): Uniform Resource Identifiers. These are web addresses in an API that provide access to data. Endpoints can allow for different HTTP methods, such as GET, POST, PUT, PATCH, and DELETE, to perform operations on data (e.g. http://example.com/users/ could have an endpoint to GET all users).

Example CRUD API

This app contains methods for Creating, Reading, Updating, and Deleting users. This sort of app is called a CRUD App and is a very popular architecture for managing data. Scroll down to see the endpoints and try them out.

Open in a new tab.

Making a CRUD Express.js App

Fork the repl at https://replit.com/@buckldav/express-api-starter. This repl uses replit’s built-in Database to store data. All of the code below will be added in app.js.

Types of Requests and Responses

These are common HTTP request and response methods and statuses.

OperationHTTP MethodSuccessful ResponseFailure Response
CreatePOST201 Created400 Bad Request
ReadGET200 OK404 Not Found
UpdatePUT200 OK404 Not Found
DeleteDELETE204 No Content204 No Content

Create User

All of the comments that start with #swagger show up in the Swagger UI documentation (accessible at /docs). Swagger UI is based on the OpenAPI schema and is a popular API client.

Post requests usually require a body (the data that you are creating on the database). The “schema” in the comments below is what will show up in the docs, but does not provide any validation (you would need to do that yourself). In this API, users are unique by username, so there is a bit of logic to check if the user already exists.

app.post("/users", jsonParser, async (req, res) => {
  // #swagger.summary = "User Create"
  // #swagger.description = "Create user route. Usernames must be unique."
  /*  #swagger.parameters['body'] = {
        in: 'body',
        description: 'Create a user',
        schema: {
          username: 'icanhazcheezburger',
          age: 29,
          about: ''
        }
  } */
  // if user name exists in db, reject new user
  const user = await db.get(req.body.username)
  if (user) {
    res.status(400).send("user already exists.")
  } else {
    await db.set(req.body.username, req.body)
    res.status(201).send("user created.")
  }
})

Read User

List all users

The list operation returns a list of all the keys.

app.get("/users", async (req, res) => {
  // #swagger.summary = "User List"
  // #swagger.description = "List all users."
  const keys = await db.list()
  res.status(200).send(JSON.stringify(keys))
})

Get one user by username

The :username in the path indicates that whatever you put in there when sending a request to that endpoint will be stored in req.params.username in the callback function. For example, if the request is sent to /users/david, then req.params.username = "david".

app.get("/users/:username", async (req, res) => {
  // #swagger.summary = "User Get"
  // #swagger.description = "Get user by username."
  const user = await db.get(req.params.username)
  if (user) {
    res.status(200).send(JSON.stringify(user))
  } else {
    res.status(404).send("user not found.")
  }
})

Update User

Put requests are a complete update of an database entry. This means that the body for the Update operation is the same as the body for the Create operation. For a partial update, (i.e., just updating the username), you could use a patch request, but put requests are more common.[citation needed]

app.put("/users/:username", async (req, res) => {
  // #swagger.summary = "User Update"
  // #swagger.description = "Update user by username."
  /* #swagger.parameters['body'] = {
        in: 'body',
        description: 'Update a user',
        schema: {
          username: 'icanhazcheezburger',
          age: 29,
          about: ''
        }
  } */
  // if user name exists in db, reject new user
  const user = await db.get(req.body.username)
  if (user) {
    await db.set(req.body.username, req.body)
    res.status(200).send("user created.")
  } else {
    res.status(404).send("user doesn't exist.")
  }
})

Delete User

app.delete("/users/:username", async (req, res) => {
  // #swagger.summary = "User Delete"
  // #swagger.description = "Delete user by username."
  const user = await db.delete(req.params.username)
  res.status(204).send("user deleted.")
})

To delete all users (clear the database), in replit’s Shell tab, run npm run clear.

Clear DB

Further Reading