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:
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] "}
]
Before starting the simulator, validate your configuration:
apicentric simulator validate --path users-api.yaml
You should see: ✅ Validation successful
apicentric simulator start --services-dir .
In a new terminal, test your API:
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
Time helpers
Faker helpers
Random helpers
Conditional 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"
}
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