Files
atelier/examples/good/api-endpoint.md
T
Jon Chery 496303471d docs(milestone): complete v0.1 — initial framework
---ci---
project: atelier
phase: 7
milestone: v0.1
status: complete
phase_role: final
milestone_complete: true
requirements:
  covered: [ATELIER-01, ATELIER-02, ATELIER-03, ATELIER-04, ATELIER-05, ATELIER-06, ATELIER-07, ATELIER-08, ATELIER-09, ATELIER-10, ATELIER-11, ATELIER-12, ATELIER-13, ATELIER-14, ATELIER-15, ATELIER-16, ATELIER-17, ATELIER-18, ATELIER-19, ATELIER-20, ATELIER-21, ATELIER-22, ATELIER-23, ATELIER-24, ATELIER-25, ATELIER-26, ATELIER-27, ATELIER-28, ATELIER-29, ATELIER-30, ATELIER-31, ATELIER-32, ATELIER-33, ATELIER-34, ATELIER-35]
  partial: []
ship:
  milestone: v0.1
  type: NFR
  tag: v0.0.7
  merge: milestone/v0.1-atelier -> main
  release: https://git.cloudinit.dev/cloudinit-bot/atelier/releases/tag/v0.0.7
---/ci---

Milestone v0.1 — Initial Framework (NFR, complete).
8 core principles (C1-C8), 11 domains, 110 domain principles, 27 derived docs, 4 good + 3 bad examples, 4 language docs, full matrix, 3 review docs.
All 35 requirements covered. 7 patches (v0.0.0 pre-execution through v0.0.7 final). v0.0.7 IS the v0.1.0 milestone release.
2026-08-05 00:36:55 +00:00

3.2 KiB
Raw Blame History

Good Example: API Endpoint

A REST endpoint that follows Atelier's API principles. Each aspect cites the principle it satisfies.

The Endpoint

// POST /v1/orders — create an order
router.post('/v1/orders', auth, validate(CreateOrderSchema), async (req, res) => {
  const { userId, items } = req.body;

  const order = await orderService.create({ userId, items });

  res.status(201).location(`/v1/orders/${order.id}`).json({
    data: order,
  });
});

What Makes It Good

Resource Naming (API P2 Clarity, P3 Predictability)

  • /v1/orders — noun, plural, lowercase, hyphenated.
  • Versioned (/v1) — P5 Versioning.
  • No verb in the URL; the HTTP method is the verb.

Method Semantics (API P1 Contract Fidelity, P6 Idempotency)

  • POST for creation. 201 on success (not 200). Location header for the new resource.
  • Idempotency key supported via middleware (omitted for brevity) — P6.

Authentication (API P8 Security, Security P1 Zero Trust)

  • auth middleware runs on every endpoint by default. No opt-in auth.
  • The endpoint does not re-implement auth; it relies on the boundary check.

Input Validation (API P8, Security P4 Input Validation)

  • validate(CreateOrderSchema) — schema-based validation at the boundary.
  • The schema (zod, joi, etc.) defines types, ranges, required fields.
  • Unknown fields rejected (additionalProperties: false in the schema).

Response Shape (API P2 Clarity)

  • { data: order } — wrapped, not a bare object. Allows adding pagination/metadata without breaking.
  • The shape is consistent across all endpoints in the API.

Error Handling (API P9 Error Transparency, Errors P1 Errors are Data)

  • Errors thrown in orderService.create are caught by centralized middleware.
  • Errors are structured: { error: { code, message, request_id } }.
  • 404 → ORDER_NOT_FOUND, 409 → DUPLICATE_ORDER, 422 → VALIDATION_FAILED.

Observability (Observability P2 Correlation, P3 Sufficient Context)

  • request_id propagated via middleware. Every log in the request includes it.
  • Significant events logged: "order created", "order creation failed".

Economy (Core C8, Performance P4 Resource Bounds)

  • The order creation is bounded in time (the service has a timeout).
  • No unbounded query; no loading all products into memory.

The Schema (for completeness)

const CreateOrderSchema = z.object({
  userId: z.string().uuid(),
  items: z.array(z.object({
    productId: z.string().uuid(),
    quantity: z.number().int().positive().max(100),
  })).min(1).max(50),
}).strict();  // additionalProperties: false
  • userId is a UUID (Data P7 Type Fidelity).
  • quantity is bounded (Performance P4).
  • items is bounded (150) (Performance P4, Security P10 Surface Minimization).
  • .strict() rejects unknown fields (Security P4).

What This Example Does NOT Do (And Why That's Good)

  • Does not return 200 on error — the status code is the first signal (API P9).
  • Does not log the request body — may contain PII (Observability P6, Security P9).
  • Does not construct SQL by string interpolation — uses a service layer (Security P5 Output Safety).
  • Does not skip auth for "internal" callers — Zero Trust (Security P1).