Building and Debugging a Local API Server on Linux

Building and Debugging a Local API Server on Linux

Learning Linux is not about memorizing commands. It is about building workflows. This note walks through a small project that connects basic Linux commands with real backend debugging tasks.

1. Why This Approach

When learning Linux, it is easy to focus on isolated commands:

1
2
3
ls
cd
rm

However, these commands only become meaningful when used in a real workflow.

Instead of treating Linux as a subject, this project treats it as a tool:

1
Run a server → send requests → inspect responses → debug failures → analyze logs

2. Basic Linux Commands in Context

Before building anything, these commands form the foundation:

1
2
3
4
5
6
7
8
pwd        # show current directory
ls # list files
cd # change directory
mkdir # create directory
touch # create file
rm # remove file
cp # copy file
mv # move or rename file

These are not just utilities. They define how you navigate and manipulate your working environment.

For example:

1
2
3
mkdir news-api
cd news-api
touch server.py

This creates a minimal project structure.

3. Running a Local Server

A simple Python HTTP server is enough to simulate a backend:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/news":
data = {"articles": [{"title": "Linux is powerful"}]}
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps(data).encode())
else:
self.send_response(404)
self.end_headers()

server = HTTPServer(("localhost", 8001), Handler)
server.serve_forever()

Running it in the background:

1
python3 -u server.py > server.log 2>&1 &

Breakdown:

1
2
3
4
-u        disable output buffering (important for logs)
> file redirect output
2>&1 merge error output
& run in background

4. Making Requests with curl

Instead of using GUI tools, requests can be tested directly:

1
curl -s http://localhost:8001/news

To inspect headers:

1
curl -I http://localhost:8001/news

The key idea:

1
curl allows you to interact with APIs at the HTTP level.

5. Parsing JSON with jq

Raw JSON is hard to read and filter. jq solves this.

Example:

1
curl -s http://localhost:8001/news | jq

Extract specific fields:

1
curl -s http://localhost:8001/news | jq -r '.articles[].title'

Important distinction:

1
2
{} → object → use .key
[] → array → use [index] or []

Examples:

1
2
3
jq '.title'
jq '.[0].title'
jq '.[].title'

Understanding this distinction avoids common errors like:

1
Cannot index object with number

6. Process Management

When running services, you need to control processes.

Check which process is using a port:

1
lsof -i :8001

Kill the process:

1
kill PID

This is essential when restarting or debugging a service.

7. Log Inspection

All server output is redirected to a log file:

1
tail -f server.log

Typical output:

1
2
GET /news 200
GET /abc 404

Filter logs:

1
grep "404" server.log

Count occurrences:

1
grep "ERROR" server.log | wc -l

This forms the basis of debugging:

1
observe → filter → quantify

8. Extending the API: Search Endpoint

A basic improvement is adding query-based filtering:

1
/news/search?q=linux

Implementation:

1
2
3
4
5
6
7
8
9
10
11
from urllib.parse import urlparse, parse_qs

parsed = urlparse(self.path)
query = parse_qs(parsed.query)

keyword = query.get("q", [""])[0].lower()

results = [
article for article in ARTICLES
if keyword in article["title"].lower()
]

Testing:

1
curl -s "http://localhost:8001/news/search?q=api" | jq -r '.articles[].title'

This introduces:

1
query parsing → filtering → structured response

9. Error Handling and Logging

Invalid endpoints:

1
curl -s http://localhost:8001/abc

Server-side logging:

1
print("ERROR: invalid endpoint accessed")

Then analyze:

1
grep "ERROR" server.log

This is the simplest form of observability.

10. Automating Log Checks

A small script can automate error detection:

1
2
3
4
5
6
7
8
9
#!/bin/bash

count=$(grep "ERROR" server.log | wc -l)

if [ "$count" -gt 0 ]; then
echo "ERROR detected"
else
echo "No errors"
fi

Run:

1
./check_error.sh

This turns manual inspection into a repeatable workflow.

11. Putting It All Together

The full workflow looks like:

1
2
3
4
5
6
1. Start server
2. Send request (curl)
3. Inspect response (jq)
4. Check logs (tail / grep)
5. Fix issue
6. Restart process (kill + run)

This is not theoretical. It is exactly how real services are debugged.

12. Final Takeaway

Linux commands are not isolated tools.

They form a pipeline:

1
filesystem → processes → network → logs → automation

The value comes from combining them:

1
curl + jq + grep + lsof + bash

This small project demonstrates how these pieces connect into a practical backend workflow.


Building and Debugging a Local API Server on Linux
http://runningcoconut.com/2026/05/03/Building-and-Debugging-a-Local-API-Server-on-Linux/
Author
Huajing Lu
Posted on
May 3, 2026
Licensed under