ABCsteps lesson path
Create Your Own API
Build an Express.js server to receive and return data so the app can do more than display a static screen. Build one artifact, keep one review trail, and make the work easy to inspect later.
- Lesson
- 13
- Time
- 45 min
- Access
- public lesson
Learning objective
Create simple endpoints with clear input and output behavior.
Lab outcome
Build an API route and call it from the frontend.
Module milestone
Build a small full-stack leaderboard with persistent data.
Lesson proof workflow
Read, build, then review the evidence.
- Step 1ReadStart with Express endpoints before touching tools.
- Step 2BuildBuild toward: Build an API route and call it from the frontend.
- Step 3ReviewReview the evidence using Client server calls.
Toolchain
Your own API turns a static interface into a system.
These are the practical surfaces used in this lesson. Learn the habit first, then connect it to the wider engineering ecosystem.
Create endpoints with clear request and response behavior.
Connect UI behavior to server responses.
Return predictable payloads the client can use.
Proof of work
Leave one inspectable trail from this lesson.
The useful output is not a passive note. It is a small artifact another person can inspect: a working file, a command result, a commit, a screenshot, a README note, or a demo link.
Lesson lab: Build an API route and call it from the frontend.
Tool and platform logos are ecosystem references only: no affiliation, endorsement, interview access, hiring promise, salary promise, or placement guarantee.
Build
Produce the artifact
Complete the lab and keep the result visible: Build an API route and call it from the frontend.
Record
Save review evidence
Capture what changed, what broke, and how Express endpoints became clearer through the work.
Explain
Write the vocabulary
Use your own words for Input output design and Client server calls; this is what makes the lesson inspectable later.
Skills companies recognize
Translate the lesson into inspectable work language.
This lesson turns one small lab into the language a learner can use in a README, demo note, or technical conversation. The point is not to collect logos; the point is to explain work clearly enough that another engineer can inspect it.
Where this skill appears
Backend and full-stack teams care less about the framework name and more about clear endpoint behavior.
Ecosystem references
Platform and company logos are ecosystem references only: no affiliation, endorsement, interview access, hiring preference, salary outcome, or placement guarantee.
README line
Name the artifact
Lab proof: Build an API route and call it from the frontend. Connect it to Express endpoints so the result reads like work, not a passive note.
Review line
Explain the stack
Use Node.js, JavaScript, JSON to explain Input output design and what changed between the first attempt and the inspected result.
Conversation line
Answer with evidence
If a team asks about Client server calls, use this proof line: Show the endpoint, sample input, sample output, error case, and the frontend call that uses it.
Proof translation
Skill signal
Express endpoints is the market word. The lesson makes it visible through a small working artifact.
Proof artifact
The inspectable artifact is: Build an API route and call it from the frontend.
Interview answer
Use Input output design and Client server calls to explain what changed, what failed, and how you verified it.
Paid guidance
Read publicly. Upgrade when guidance will help you finish.
This lesson remains part of the public written syllabus. Paid help is online-only and human-led: video walkthroughs as they roll out, live class context, WhatsApp Q&A, and project review around the same work.
No account wall, automated checkout, or placement promise is introduced here. Enrollment stays human-led by WhatsApp or call, and the useful proof remains the learner's own artifact.
Public
Written lesson stays open
Read the prepare and review material for lesson 13 on the public site before buying anything.
Recorded
Recorded and live guidance clarify the work
Paid guidance can add founder-led video walkthroughs as they roll out and live online class context; the teaching explains the work, but does not replace the written lesson.
Human
Questions use real context
When stuck, useful guidance starts from the route, error, screenshot, repo fragment, and the lab artifact: Build an API route and call it from the frontend.
Phase 1 · Briefing
Lesson briefing
Before You Study (5 mins)
Lesson focus: Until now, you've called other people's APIs (Lesson 09: weather, quotes, LLMs). Today you flip the relationship and become the API provider. Your backend will expose a real REST API for a Snake-game leaderboard — GET to read scores, POST to add one, DELETE to clear them — with proper request validation, error handling, and the conventions every professional API follows. By the end, your frontend talks to your backend over an interface you designed and own.
What you should have ready:
- Lesson 12's
backend/directory with Express, CORS, and the/api/healthroute working -
nodemonrunning so the server hot-reloads as you edit - A REST client for testing — your terminal
curlis fine, Insomnia or Bruno are free GUIs - About 60 minutes
- Patience for debugging — half of API work is fixing the 400-status response that just came back
The Concept
A REST API is a way of designing HTTP endpoints around a small, consistent vocabulary. The word "REST" stands for Representational State Transfer — but the practical meaning today is: resources have URLs, and HTTP verbs do operations on those resources. That's the entire idea.
The vocabulary you saw in Lesson 09 from the consumer side, now applied as a designer:
| Verb | Path | Operation |
|---|---|---|
GET /scores | Read all scores | |
GET /scores/42 | Read score with ID 42 | |
POST /scores | Create a new score | |
PUT /scores/42 | Replace score 42 entirely | |
PATCH /scores/42 | Partially update score 42 | |
DELETE /scores/42 | Remove score 42 |
The same path with different verbs does different things. This is RESTful design's core elegance: a small, predictable surface that any developer can navigate without docs.
A real API has more than just routes. It has a request-handling pipeline that is the same shape on every server you'll ever build:
HTTP request arrives
│
▼
1. Parse body / query params (express.json())
│
▼
2. Validate input (is name a non-empty string? is score a number?)
│
▼
3. Authenticate (who is the caller? do they have a valid token?) [later lessons]
│
▼
4. Authorize (are they allowed to do THIS action?) [later lessons]
│
▼
5. Execute business logic (compute, query DB, call other services)
│
▼
6. Format response (set status code, return JSON)
│
▼
HTTP response sent
This pipeline is implemented in Express through middleware — small functions that run in order, each one either passing control to the next (next()) or short-circuiting with a response. Authentication, validation, logging, error handling — they're all middleware. Once this clicks, every Express server feels like the same shape.
A few conventions every well-designed API follows:
- Use the right verb.
GETdoesn't change state.POSTcreates.DELETEremoves. Mixing them up confuses everyone, including future-you. - Return the right status code.
200 OKfor read,201 Createdfor write,204 No Contentfor delete,400 Bad Requestfor validation failures,404 Not Foundfor missing resources,500 Internal Server Errorfor crashes. The status code is the API speaking to you in its own language; respect it. - Return JSON, always. Even errors (
{ "error": "name is required" }). Never plain text or HTML. - Validate everything. A
POST /scoreswithscore: "🐍"instead of a number should fail at validation, not at the database. - Be idempotent where you can. A
PUT /scores/42with the same body should produce the same end state on every call. POST is the exception.
Today we'll build a toy in-memory leaderboard — scores stored in a JavaScript array, lost on server restart. Lesson 14 replaces the array with a real SQLite database. The route handlers and the API design stay identical; only the storage changes. This is a deliberate decoupling: API surface is the contract, storage is the implementation.
The companion article for the consumer side of this lesson is What is an API and How Do APIs Actually Work — which now reads differently because you're about to design your own.
Quick Concepts
| Term | Simple Meaning |
|---|---|
| REST | Resources have URLs; HTTP verbs do operations on them |
| Endpoint | A specific URL + verb combination handled by your server |
| Route handler | The function that runs when a request hits an endpoint |
| Middleware | A function in the request-processing pipeline (parse, auth, log, ...) |
req.body | The parsed JSON body of a POST/PUT/PATCH request |
req.params | URL path parameters — /scores/:id makes req.params.id available |
req.query | Query string parameters — /scores?limit=10 makes req.query.limit available |
| Validation | Checking inputs are well-formed before running business logic |
What We Will Build
By the end of this lesson, you will have done these specific things:
- Set up an in-memory store in
server.js— a simple JavaScript array we can read and write to:javascriptlet scores = [] // [{ id, name, score, createdAt }] let nextId = 1 - Built
GET /api/scores— returns the array, sorted by score descending, optionally paginated via?limit=10:javascriptapp.get('/api/scores', (req, res) => { const limit = Math.min(Number(req.query.limit) || 10, 100) const sorted = [...scores].sort((a, b) => b.score - a.score).slice(0, limit) res.json({ scores: sorted, count: sorted.length, total: scores.length }) }) - Built
POST /api/scores— accepts{ name, score }, validates them, creates a new entry, returns it with a201 Created:javascriptapp.post('/api/scores', (req, res) => { const { name, score } = req.body if (typeof name !== 'string' || name.trim().length < 1 || name.length > 30) { return res.status(400).json({ error: 'name must be a 1-30 char string' }) } if (typeof score !== 'number' || score < 0 || !Number.isFinite(score)) { return res.status(400).json({ error: 'score must be a non-negative number' }) } const entry = { id: nextId++, name: name.trim(), score, createdAt: new Date().toISOString() } scores.push(entry) res.status(201).json(entry) }) - Built
GET /api/scores/:id— returns one specific score by ID;404 Not Foundif it doesn't exist. - Built
DELETE /api/scores/:id— removes a score;204 No Contenton success. - Tested every endpoint with
curl— the discipline of testing your own API from the terminal builds the muscle every senior backend engineer has:bashcurl -s http://localhost:3001/api/scores | jq . curl -s -X POST http://localhost:3001/api/scores \ -H 'Content-Type: application/json' \ -d '{"name":"Divyanshu","score":1500}' | jq . - Triggered every error path on purpose — sent a missing name (expect 400), sent an invalid score (expect 400), fetched a non-existent ID (expect 404), so you've seen the failure modes of your own API.
- Wired the frontend — your Snake game now calls
POST /api/scoreson game-over andGET /api/scoreson game-start. The leaderboard appears on screen. - Added one global error-handler middleware at the bottom of your server so any uncaught error returns a clean
500 Internal Server ErrorJSON instead of an HTML stack trace:javascriptapp.use((err, req, res, next) => { console.error(err) res.status(500).json({ error: 'Internal server error' }) })
Step 9 is what separates a real API from a hello-world demo. In production, something will throw; the question is what the user sees when it does.
Think About
Before studying, consider:
- If you accept any payload
POST /api/scoressends — including{ "score": 999999999 }from a malicious client — your leaderboard fills with garbage in 60 seconds. Where does the rule "scores must be plausible" belong? (Hint: not just on the frontend. Backend validation is non-negotiable.) - The leaderboard you build today loses all data on server restart. That's fine for development. What changes the moment you put this in production with real users? (Hint: the storage layer becomes the most important part of the system. Lesson 14 builds it.)
By the End
After this lesson, you'll:
- Have a working CRUD API for scores (Create, Read one, Read many, Delete)
- Know the right HTTP verb for each operation
- Know the right status code for each outcome (200 / 201 / 204 / 400 / 404 / 500)
- Validate every input before touching state
- Have a global error-handling middleware
- Test your own API from
curland from your frontend - Be ready for Lesson 14 — replacing the in-memory array with a real database
You are the chef now. The world places orders. 👨🍳
Next lesson · 14
Databases: Store Data Permanently
Use SQLite to understand tables, records, and persistence without adding unnecessary infrastructure.