Skip to main content
Apicentric makes it easy to create realistic mock APIs using simple YAML configuration files. This guide walks you through creating your first mock API and progressively adding advanced features.

Prerequisites

  • Apicentric CLI installed
  • Basic understanding of REST APIs
  • A text editor

Your first service definition

Create a file named users-api.yaml with a basic service definition:
users-api.yaml
name: users-api
server:
  port: 9000
  base_path: /api/v1
endpoints:
  - method: GET
    path: /users
    responses:
      200:
        content_type: application/json
        body: |
          [
            {"id": 1, "name": "Alice", "email": "[email protected]"},
            {"id": 2, "name": "Bob", "email": "[email protected]"}
          ]
1
Validate your service
2
Before starting the simulator, validate your configuration:
3
apicentric simulator validate --path users-api.yaml
4
You should see: ✅ Validation successful
5
Start the simulator
6
Start your mock API:
7
apicentric simulator start --services-dir .
8
Test your endpoint
9
In a new terminal, test your API:
10
curl http://localhost:9000/api/v1/users

Adding path parameters

You can create dynamic endpoints with path parameters:
endpoints:
  - method: GET
    path: /users/{id}
    description: Get user by ID
    responses:
      200:
        content_type: application/json
        body: |
          {
            "id": "{{params.id}}",
            "name": "User {{params.id}}",
            "email": "user{{params.id}}@example.com"
          }
      404:
        content_type: application/json
        body: |
          {
            "error": "User not found",
            "message": "No user with ID {{params.id}}"
          }
Test it:
curl http://localhost:9000/api/v1/users/42

Using fixtures for reusable data

Fixtures let you define reusable data that can be referenced across multiple endpoints:
name: users-api
server:
  port: 9000
  base_path: /api/v1

fixtures:
  users:
    - id: 1
      name: "Alice"
      email: "[email protected]"
      role: "admin"
    - id: 2
      name: "Bob"
      email: "[email protected]"
      role: "user"

endpoints:
  - method: GET
    path: /users
    responses:
      200:
        content_type: application/json
        body: |
          [
            {{#each fixtures.users}}
            {
              "id": {{id}},
              "name": "{{name}}",
              "email": "{{email}}",
              "role": "{{role}}"
            }{{#unless @last}},{{/unless}}
            {{/each}}
          ]

Dynamic responses with Handlebars

Apicentric uses Handlebars templates for dynamic response generation:

Accessing request data

endpoints:
  - method: POST
    path: /users
    responses:
      201:
        content_type: application/json
        body: |
          {
            "id": {{faker "datatype.number" min=1000 max=9999}},
            "name": "{{request.body.name}}",
            "email": "{{request.body.email}}",
            "created_at": "{{now}}"
          }

Available template helpers

body: |
  {
    "timestamp": "{{now}}",
    "formatted": "{{now format='%Y-%m-%d'}}",
    "expires_at": "{{now offset=3600}}"
  }

Handling different HTTP methods

Create a full CRUD API:
endpoints:
  # List all
  - method: GET
    path: /products
    responses:
      200:
        content_type: application/json
        body: '[]'

  # Get one
  - method: GET
    path: /products/{id}
    responses:
      200:
        content_type: application/json
        body: '{"id": "{{params.id}}", "name": "Product {{params.id}}"}'

  # Create
  - method: POST
    path: /products
    responses:
      201:
        content_type: application/json
        body: '{"id": {{faker "datatype.number"}}, "name": "{{request.body.name}}"}'

  # Update
  - method: PUT
    path: /products/{id}
    responses:
      200:
        content_type: application/json
        body: '{"id": "{{params.id}}", "updated": true}'

  # Delete
  - method: DELETE
    path: /products/{id}
    responses:
      204:
        content_type: text/plain
        body: ''

Adding CORS support

Enable CORS for frontend development:
server:
  port: 9000
  base_path: /api
  cors:
    enabled: true
    origins: ["http://localhost:3000", "http://localhost:5173"]
Use origins: ["*"] for development, but specify exact origins for production.

Simulating delays

Add realistic network latency:
endpoints:
  - method: GET
    path: /slow-endpoint
    responses:
      200:
        content_type: application/json
        body: '{"message": "This was slow"}'
        delay_ms: 2000
Or add random delays across all endpoints:
behavior:
  response_delays:
    min_ms: 100
    max_ms: 500

Working with query parameters

Access query parameters in your responses:
endpoints:
  - method: GET
    path: /search
    parameters:
      - name: q
        in: query
        required: true
        type: string
      - name: limit
        in: query
        required: false
        type: integer
    responses:
      200:
        content_type: application/json
        body: |
          {
            "query": "{{query.q}}",
            "limit": "{{query.limit}}",
            "results": []
          }
Test it:
curl "http://localhost:9000/api/search?q=hello&limit=10"

Conditional responses

Return different responses based on request data:
endpoints:
  - method: POST
    path: /login
    responses:
      200:
        condition: "{{eq request.body.password 'secret'}}"
        content_type: application/json
        body: |
          {
            "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
            "user": {"id": 1, "email": "{{request.body.email}}"}
          }
      401:
        condition: "{{ne request.body.password 'secret'}}"
        content_type: application/json
        body: |
          {
            "error": "Invalid credentials"
          }

Adding custom headers

Return custom headers in responses:
endpoints:
  - method: POST
    path: /auth
    responses:
      200:
        content_type: application/json
        headers:
          X-Auth-Token: "abc123token"
          Set-Cookie: "session=xyz; HttpOnly; Secure"
          X-Rate-Limit: "100"
        body: '{"authenticated": true}'

Multiple response scenarios

Define multiple status codes for the same endpoint:
endpoints:
  - method: GET
    path: /api/status
    responses:
      200:
        content_type: application/json
        body: '{"status": "ok"}'
      500:
        content_type: application/json
        body: '{"status": "error", "message": "Internal server error"}'
      503:
        content_type: application/json
        body: '{"status": "maintenance", "message": "Service under maintenance"}'
By default, Apicentric returns the first matching successful response (2xx). You can use scenarios to control which response is returned. See the contract testing workflow guide for more details.

Next steps

Request validation

Add schema validation to your endpoints

Import specs

Convert OpenAPI, Postman, or WireMock specs

Export specs

Generate OpenAPI specs and TypeScript types

Dockerize services

Run your mocks in Docker containers

Build docs developers (and LLMs) love