Menu

Backend Engineering Foundations

Learn Backend Engineering Foundations for Backend Engineer for free: roadmap, examples, subskills, and a skill exam.

Published: January 20, 2026 | Updated: January 20, 2026

Who this is for

You are starting or formalizing your path as a Backend Engineer. You may know a programming language already, but want the practical foundations to ship reliable APIs and services the team can trust.

Prerequisites

  • Comfort with at least one programming language (e.g., JavaScript/TypeScript, Python, Go, Java, or C#).
  • Basic command-line and Git usage.
  • Optional but helpful: familiarity with JSON and simple HTTP requests.

Why this matters for Backend Engineer

Backend Engineering Foundations give you the building blocks to design HTTP APIs, handle errors predictably, secure endpoints, test behavior, and debug with confidence. With these skills, you can:

  • Design clear, stable REST endpoints that are easy for clients to consume.
  • Structure code and data thoughtfully for performance and maintainability.
  • Catch failures early with testing and logging that tell the right story.
  • Protect user data with authentication, authorization, and security best practices.

Practical roadmap

1) Speak HTTP fluently

Master methods, status codes, headers, content negotiation, and REST resource modeling.

Milestone checklist
  • Use GET/POST/PUT/PATCH/DELETE appropriately.
  • Return correct status codes and error bodies.
  • Understand idempotency and safe methods.

2) Design APIs that age well

Establish resource naming, pagination, filtering, versioning, and consistent responses.

Milestone checklist
  • Stable paths and nouns for resources.
  • Query params for filtering/sorting/pagination.
  • Versioning plan (e.g., /v1 or header-based).

3) Handle failures like a pro

Centralized error handling, structured logging, and correlation IDs for tracing.

Milestone checklist
  • Consistent error schema (code, message, details).
  • Logs include level, context, and request ID.
  • Graceful fallbacks and retries where safe.

4) Protect your endpoints

Apply authentication (e.g., JWT, sessions) and authorization (RBAC/ABAC). Cover security basics.

Milestone checklist
  • Verify tokens and enforce scopes/roles.
  • Validate input; avoid injection and common risks.
  • Follow the principle of least privilege.

5) Test and debug effectively

Write unit and integration tests, use fixtures, and debug with logs and small repros.

Milestone checklist
  • Fast unit tests for pure logic.
  • Integration tests for endpoints and flows.
  • Debug playbook for incident triage.

Worked examples

1) Minimal health check endpoint (Node.js Express)
const express = require('express');
const app = express();

app.get('/health', (req, res) => {
  res.set('Cache-Control', 'no-store');
  res.status(200).json({ status: 'ok', time: new Date().toISOString() });
});

app.listen(3000, () => console.log('Listening on :3000'));

Notes: GET is safe and idempotent. Health endpoints should avoid sensitive data and be fast.

2) RESTful pagination with limit/offset (Node.js Express)
app.get('/v1/users', async (req, res) => {
  const limit = Math.min(parseInt(req.query.limit || '20'), 100);
  const offset = parseInt(req.query.offset || '0');

  // Fetch from data source (pseudo)
  const items = await db.users.find({ limit, offset });
  const total = await db.users.count();

  res.status(200).json({
    items,
    page: { limit, offset, total }
  });
});

Notes: Cap limits to protect servers. Return paging metadata to help clients render UIs.

3) Centralized error handler + structured logging
const pino = require('pino')();

function asyncWrapper(fn) {
  return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
}

app.get('/v1/items/:id', asyncWrapper(async (req, res) => {
  const item = await db.items.get(req.params.id);
  if (!item) {
    const err = new Error('Not Found');
    err.status = 404; err.code = 'ITEM_NOT_FOUND';
    throw err;
  }
  res.json(item);
}));

app.use((err, req, res, next) => {
  const status = err.status || 500;
  pino.error({
    level: 'error',
    code: err.code || 'INTERNAL_ERROR',
    msg: err.message,
    path: req.path,
    requestId: req.headers['x-request-id'] || null
  });
  res.status(status).json({
    error: { code: err.code || 'INTERNAL_ERROR', message: err.message }
  });
});

Notes: Centralize error formatting; log with context; never leak secrets to clients.

4) JWT auth middleware (Node.js Express)
const jwt = require('jsonwebtoken');
const JWKS_PUBLIC_KEY = process.env.PUBLIC_KEY_PEM;

function auth(requiredScope) {
  return (req, res, next) => {
    const header = req.headers.authorization || '';
    const token = header.startsWith('Bearer ') ? header.slice(7) : null;
    if (!token) return res.status(401).json({ error: { code: 'UNAUTHENTICATED' } });
    try {
      const payload = jwt.verify(token, JWKS_PUBLIC_KEY, { algorithms: ['RS256'] });
      if (requiredScope && !payload.scopes?.includes(requiredScope)) {
        return res.status(403).json({ error: { code: 'FORBIDDEN' } });
      }
      req.user = payload;
      next();
    } catch (e) {
      return res.status(401).json({ error: { code: 'INVALID_TOKEN' } });
    }
  };
}

app.get('/v1/me', auth('read:profile'), (req, res) => {
  res.json({ id: req.user.sub, email: req.user.email });
});

Notes: Separate authentication from authorization. Verify algorithm and key; check scopes/roles.

5) Unit + integration tests (Python + Flask + pytest)
# app.py
from flask import Flask, jsonify
app = Flask(__name__)

@app.get('/health')
def health():
    return jsonify({ 'status': 'ok' }), 200

# pure function to unit test

def add_tax(amount: float, rate: float) -> float:
    return round(amount * (1 + rate), 2)

# test_app.py
from app import app, add_tax

def test_add_tax_unit():
    assert add_tax(100, 0.2) == 120.00

def test_health_integration():
    client = app.test_client()
    resp = client.get('/health')
    assert resp.status_code == 200
    assert resp.get_json()['status'] == 'ok'

Notes: Keep pure logic in functions for fast unit tests; use framework test clients for integration.

Drills and exercises

  • [ ] Return the correct status code for these actions: create (201), update (200/204), delete (204), not found (404), validation error (422/400).
  • [ ] Add pagination to a list endpoint with limit/offset and cap limit to 100.
  • [ ] Implement centralized error handling that returns a consistent error JSON.
  • [ ] Add request IDs to logs and echo them back in responses.
  • [ ] Implement a JWT-protected endpoint and verify a required scope or role.
  • [ ] Write one unit test and one integration test for the same feature.
  • [ ] Add basic input validation to an endpoint and reject invalid data.

Common mistakes and debugging tips

  • Mixing resource actions with verbs in paths: Prefer /v1/users/123 over /v1/getUser. Use HTTP methods to convey actions.
  • Leaking stack traces: Log stack traces internally; return clean, user-safe error messages and codes.
  • Wrong status codes: 200 for success, 201 for creation, 204 for no content, 400/422 for client errors, 401 for unauthenticated, 403 for unauthorized, 404 for missing, 500 for server errors.
  • Trusting client input: Validate and sanitize. Enforce types and bounds server-side.
  • No timeouts/retries: Use reasonable timeouts and cautious retries for idempotent operations only.
  • Missing tests: Start with unit tests for core logic, then add integration tests for key paths.
  • Opaque logs: Add context (request ID, user ID, resource ID) and use structured logs (JSON).
Debugging checklist
  • Reproduce with the smallest possible request (use the same payload the client sends).
  • Check logs with the correlation/request ID across services.
  • Verify assumptions: headers present, auth claims correct, database returns expected rows.
  • Toggle log level to debug temporarily and capture a timeline.
  • Write a failing test and fix it to prevent regressions.

Mini project: Task Tracker API

Build a small REST API to manage tasks with users.

Requirements
  • Endpoints: POST /v1/tasks, GET /v1/tasks, GET /v1/tasks/{id}, PATCH /v1/tasks/{id}, DELETE /v1/tasks/{id}
  • Fields: id, title, status (todo|doing|done), createdAt, updatedAt, ownerId
  • Auth: JWT required for all endpoints; only owners can update/delete their tasks.
  • Pagination: limit/offset on list; support status filter.
  • Errors: consistent JSON error responses with codes.
Acceptance checks
  • [ ] Creating a task returns 201 with the new resource.
  • [ ] Unauthorized access returns 401; forbidden cross-user updates return 403.
  • [ ] Listing supports limit, offset, and status filter.
  • [ ] Invalid fields return 422 with details.
  • [ ] Logs contain request ID and user ID where applicable.
  • [ ] Unit tests cover task validation; integration tests cover create/list/update/happy and error paths.
Stretch goals
  • [ ] ETag or If-None-Match support on GETs for caching.
  • [ ] Soft deletes with deletedAt and filtering.
  • [ ] Basic rate limiting per user or IP.

Subskills

Master these subskills to complete your foundation:

HTTP And REST Fundamentals

Understand HTTP methods, status codes, headers, RESTful resource modeling, idempotency, and content negotiation.

API Design Principles

Design resource-oriented URLs, pagination, filtering, sorting, versioning, and consistent response shapes.

Data Structures And Algorithms Basics

Use arrays, maps, sets, stacks/queues, and Big-O thinking to choose efficient approaches for common backend tasks.

Error Handling And Logging

Centralize error responses, create stable error codes, emit structured logs with context and correlation IDs.

Authentication And Authorization Basics

Implement JWT/session auth, verify tokens, and enforce roles/scopes (RBAC/ABAC) using least privilege.

Security Fundamentals

Validate input, avoid injection, protect secrets, use HTTPS, and handle common risks safely.

Testing Mindset And Debugging

Write unit and integration tests, isolate side effects, and follow a clear debugging playbook.

Learning path

  • Finish these foundations and ship the mini project.
  • Move on to databases and storage models (SQL/NoSQL), then caching and background jobs.
  • Add observability: metrics, tracing, dashboards, and alerting.
  • Learn containerization and deployment basics to run your service reliably.

Practical projects to try next

  • Notes API with full-text search and tag filtering.
  • URL shortener with rate limiting and click analytics.
  • Feature-flag service with RBAC and audit logs.

Next steps

  • Pick one language/framework and implement the mini project end-to-end.
  • Add logging, auth, pagination, and tests as described.
  • Take the skill exam below. Anyone can take it; logged-in users have their progress saved automatically.

Backend Engineering Foundations — Skill Exam

This exam checks your understanding of backend foundations: HTTP/REST, API design, auth, security, errors/logging, testing, and debugging. You can take it for free. Anyone can attempt multiple times; if you are logged in, your progress and best score are saved automatically.Choose the best answers. Some questions may have multiple correct choices. Aim for at least 70% to pass.

13 questions70% to pass

Have questions about Backend Engineering Foundations?

AI Assistant

Ask questions about this tool