Course outline · 0% complete

0/29 lessons0%

Course overview →

What a Backend Is

lesson 1-1 · ~9 min · 1/29

Two halves of every app

When you open a website, two programs cooperate.

  • The frontend is the code running in your browser: the buttons, text, and colors you see.
  • The backend is a program running on another computer, called a server, somewhere else in the world. It stores the data, checks passwords, and decides what each user is allowed to do.

The browser is called the client because it asks for things. The server answers. Every interaction follows the same cycle:

  1. The client sends a request: "give me the profile page for user 42".
  2. The server runs some code: look up user 42, check permissions.
  3. The server sends back a response: the data, plus a code saying how it went.

This course teaches you to write the program in the middle, using Node.js, a way to run JavaScript outside the browser.

Clientbrowser or appasks for thingsServeryour Node.js codeanswersrequest: GET /users/42response: 200 + data
The request and response cycle. A request travels from the client to the server, your code runs, and a response travels back.

Where a password is checked

When you type a password into a login form and press Submit, the part of the app that checks whether it is correct is the backend, because the real password data must stay on the server.

The browser can check the format, such as whether the field is empty or too short, and it can never hold the real password data. Anyone can open dev tools and change frontend code, so a check that lives in the browser is a suggestion rather than a rule.

The backend is the only place you can trust, so all real checks happen there. A frontend check is a convenience that saves a round trip, and the server repeats every one of them regardless.

This rule, never trust the client, comes back in the validation and auth units, and it is the single most useful habit in backend work.

A server is just a function

Strip away the network for a second. A backend is a function that takes a request and returns a response.

  • A request has a method (like GET, meaning "read something"), a path (like /hello), and sometimes data.
  • A response has a status code (a number: 200 means OK, 404 means not found) and a body (the content).

You can write that function in plain JavaScript right now, no server needed. Run the example below. The handle function is the entire idea of a backend in ten lines.

A pretend server in ten lines

handle takes a request object and returns a response object, which is the entire idea of a backend with the network removed.

// A backend, minus the network: request in, response out
function handle(request) {
  if (request.path === "/hello") {
    return { status: 200, body: "Hello from the backend!" };
  }
  return { status: 404, body: "Not found" };
}

console.log(JSON.stringify(handle({ method: "GET", path: "/hello" })));
console.log(JSON.stringify(handle({ method: "GET", path: "/missing" })));

Output

{"status":200,"body":"Hello from the backend!"}
{"status":404,"body":"Not found"}

Each printed line matches one return statement. The first call finds the matching path and returns early, and the second falls past the if to the final line.

That final return is the fallback, and every real server has one. A request for a path nobody wrote code for still has to produce an answer, and 404 is what "I looked and there is nothing here" sounds like.

The function is pure in the sense from Advanced JavaScript, since the same request object always produces the same response and nothing outside is touched. Real handlers reach out to databases and stop being pure, and the shape stays exactly this.

Note that status and body are just properties on an ordinary object here. Later lessons hand those values to Node's http module instead of returning them, and the decision about what they should be is made in code that looks like this.

Adding a second route

A new path means a new if before the fallback, so /about answers 200 while unknown paths still answer 404.

function handle(request) {
  if (request.path === "/hello") {
    return { status: 200, body: "Hello from the backend!" };
  }
  if (request.path === "/about") {
    return { status: 200, body: "About us" };
  }
  return { status: 404, body: "Not found" };
}

console.log(JSON.stringify(handle({ method: "GET", path: "/about" })));
console.log(JSON.stringify(handle({ method: "GET", path: "/missing" })));

Output

{"status":200,"body":"About us"}
{"status":404,"body":"Not found"}

The new block is a copy of the /hello block with two strings changed, which is how routing grows in its simplest form. Order matters only in that the 404 must stay last, since a return above it would make everything below unreachable.

The comparison uses === on the whole path string, so /about matches and /about/ and /About do not. Exact string matching is the honest starting point, and unit 3 replaces it with a route table that handles trailing slashes and path parameters.

This is also where the pattern starts to strain. Ten routes means ten near-identical blocks, and the eleventh is where somebody forgets a return and two routes appear to merge, which is the argument for the table-driven approach later.