Skip to content

Repository files navigation

Provision API

Small TypeScript + Express API for a mock infrastructure provisioning workflow to demonstrate clean structure, idempotency, validation, and basic API security.

Run

Install dependencies:

npm install

Start locally:

npm run dev

The app runs on http://localhost:3001.

Run tests:

npm test

Build Docker image:

docker build -t provision-api .
docker run -p 3001:3001 -e API_KEY=my-secret provision-api

Copy .env.example to .env for local development and replace placeholder values as needed.

API

All endpoints require x-api-key, except /api/health.

Authentication is intentionally lightweight in this repo. I used a single x-api-key header check rather than Basic Auth to keep the implementation small and focused on the core workflow. The default fallback key in code (dev-placeholder-api-key) is only a development placeholder, not a real secret. In a production setting, the key would come from environment configuration or secret-management tooling rather than a hardcoded fallback.

POST /api/provision

Creates a provisioning request.

Example body:

{
  "idempotencyKey": "deploy-run-42",
  "requestor": "engineer@example.com",
  "environment": "prod",
  "workloadName": "payments-api",
  "components": ["compute", "key-vault"]
}

Responses:

  • 201 created
  • 200 repeated request with same idempotency key and same payload
  • 400 invalid request or failed business rule
  • 401 missing or invalid API key
  • 409 same idempotency key used with different payload

GET /api/provision/:requestId

Returns a provisioning request by ID.

Responses:

  • 200 found
  • 404 not found

GET /api/health

Returns a simple health response.

Business rules

  • workloadName must be kebab-case
  • prod requests must include "key-vault" in components

Design choices

The code structure is split into intentionally lightweight layers:

  • domain/: entity definitions and domain rule validation
  • application/: use-case logic and idempotency handling
  • infrastructure/: in-memory repository
  • http/: routes, handlers, validation middleware, auth middleware, error middleware
  • errors/: common error types and parsing/validation helpers

The code is intentionally lightweight, with clear boundaries for testability and replaceable persistence.

Storage

The repository is in-memory for simplicity, but sits behind a persistence boundary so it can be swapped for a database-backed implementation later.

Internally, it uses two Maps to model two lookup paths:

  • one primary map stores the actual provisioning request by requestId
  • one secondary map stores idempotencyKey -> requestId

This avoids duplicating the full request object under two different keys and mirrors the idea of a primary record store plus a secondary index.

Notes

Idempotency

Repeated requests are matched by idempotencyKey. If the payload is identical, the original request is returned. If the payload differs, the API returns 409.

Only caller-supplied fields are compared:

  • requestor
  • environment
  • workloadName
  • components

Generated fields such as requestId, status, and createdAt are excluded from comparison.

Validation

Validation is intentionally split into two layers:

  • HTTP boundary validation in middleware using Zod
  • business rule validation in the domain layer

Request-shape validation includes:

  • idempotencyKey, requestor, and components must not be empty
  • environment must be one of dev, test, or prod
  • workloadName must be between 3 and 30 characters

Business rule validation includes:

  • workloadName must be kebab-case
  • prod requests must include "key-vault" in components

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages