REST API Reference Labs
Copy-adapt patterns for Node, FastAPI, and Laravel.
This page keeps the framework-heavy material separate from the concept pages. Use it when you want implementation references for CRUD, auth, uploads, streaming, WebSockets, OpenAPI, Postman, and client code.
Shared data model and endpoint contract
Core entities
- `users`: login principals
- `items`: business objects with JSON metadata
- `attachments`: uploaded files linked to items
Endpoint set
POST /oauth/token- Demo auth endpoint that returns a bearer token for tutorials and lab flows.POST /v1/items- Create an item with a JSON metadata payload.GET /v1/items?limit=...&cursor=...- Cursor pagination pattern for stable list traversal.GET /v1/items/{id}- Read a single item, often with attachments or related records.PATCH /v1/items/{id}- Partial update using merge-style behavior.PATCH /v1/items/{id}/metadata- JSON_SET style update for nested JSON fields.POST /v1/items/{id}/attachments- Multipart upload flow.GET /v1/stream/items- SSE stream for near real-time stats or event updates./ws- WebSocket endpoint for echo or broadcast patterns.
Node.js lab
Express plus Sequelize works well for classic HTTP resource APIs, file uploads, and JSON column updates.
import express from "express";
import multer from "multer";
const app = express();
app.use(express.json());
const upload = multer({ dest: "uploads/" });
app.post("/v1/items", requireAuth, async (req, res) => {
const item = await Item.create({ name: req.body.name, metadata: req.body.metadata || {} });
res.status(201).json(item);
});
app.patch("/v1/items/:id/metadata", requireAuth, async (req, res) => {
await sequelize.query(
"UPDATE items SET metadata = JSON_SET(metadata, ?, CAST(? AS JSON)) WHERE id = ?",
{ replacements: [req.body.path, JSON.stringify(req.body.value), Number(req.params.id)] }
);
res.json(await Item.findByPk(req.params.id));
});
app.get("/v1/stream/items", requireAuth, async (req, res) => {
res.setHeader("Content-Type", "text/event-stream");
const timer = setInterval(async () => {
res.write(`data: ${JSON.stringify({ count: await Item.count() })}\n\n`);
}, 1000);
req.on("close", () => clearInterval(timer));
});
FastAPI lab
FastAPI fits strongly typed Python services, SQLAlchemy sessions, and built-in WebSocket support.
@app.post("/v1/items", dependencies=[Depends(require_user)])
def create_item(payload: dict, db: Session = Depends(get_db)):
item = Item(name=payload["name"], metadata=payload.get("metadata", {}))
db.add(item)
db.commit()
db.refresh(item)
return item
@app.patch("/v1/items/{item_id}/metadata", dependencies=[Depends(require_user)])
def json_set(item_id: int, payload: dict, db: Session = Depends(get_db)):
db.execute(
text("UPDATE items SET metadata = JSON_SET(metadata, :path, CAST(:value AS JSON)) WHERE id = :id"),
{"path": payload["path"], "value": json.dumps(payload["value"]), "id": item_id},
)
db.commit()
return db.get(Item, item_id)
@app.websocket("/ws")
async def ws(websocket: WebSocket):
await websocket.accept()
while True:
msg = await websocket.receive_text()
await websocket.send_text(json.dumps({"type": "echo", "msg": msg}))
Laravel lab
Laravel keeps migrations, model casting, validation, auth, and file handling in one familiar stack.
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->string('name', 190);
$table->json('metadata');
$table->timestamps();
});
class Item extends Model {
protected $fillable = ['name', 'metadata'];
protected $casts = ['metadata' => 'array'];
}
class ItemController extends Controller {
public function update(Request $request, int $id) {
$item = Item::findOrFail($id);
$patch = $request->input('metadataPatch', []);
$item->metadata = array_merge($item->metadata ?? [], $patch);
if ($request->has('name')) $item->name = $request->input('name');
$item->save();
return $item;
}
}
Client and CLI examples
Use curl first when debugging. It removes browser complexity and lets you verify the exact request shape quickly.
# Create item
curl -s http://localhost:3000/v1/items \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Camera","metadata":{"brand":"Sony","specs":{"mp":24}}}'
# JSON_SET patch
curl -s http://localhost:3000/v1/items/1/metadata \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"path":"$.flags.featured","value":true}'
OpenAPI and tooling
- Use OpenAPI 3.1 to describe endpoints, parameters, request bodies, and response contracts.
- Swagger UI can render interactive docs from the OpenAPI file.
- Postman collections are useful for manual testing, while Newman runs those collections in CI.
- OpenAPI generators can create SDKs and server stubs from the contract.
openapi: 3.1.0
info:
title: Items API
version: 1.0.0
paths:
/v1/items:
get:
summary: List items (cursor pagination)
post:
summary: Create item
/v1/items/{id}/metadata:
patch:
summary: Update JSON path via JSON_SET