Runtime
Runtime validation confirms whether domain and API decisions behave as expected under real query usage. It is the layer where your model goes from design to execution — and where you catch issues before your consumers do.
Runtime Purpose
The runtime answers practical questions early in your development process:
- Are field shapes predictable and consistent?
- Are relation lookups coherent and correctly nested?
- Do pagination and sorting assumptions hold on the imported data?
- Do filter expressions match the correct subset of records?
- Are null values handled the way your consumers expect?
By validating these behaviors during modeling — not after implementation — you eliminate an entire category of integration bugs.


Runtime query panel for live behavior checks.
How the Mock Runtime Works
The mock runtime engine is the core of Mockomat. It accepts GraphQL queries and translates them into MongoDB operations through a four-stage pipeline:
1. GraphQL Request Parser
The incoming query string is parsed into an abstract syntax tree (AST). This stage validates query syntax and extracts the requested fields, arguments, and nested selections.
2. Query Planner
The AST is analyzed alongside your model metadata (entity definitions, attribute flags, relation configurations) to create an execution plan. The planner determines:
- Which MongoDB collections to query
- Which fields to project
- What filter and sort operations to apply
- Which relations need to be resolved
3. MongoDB Query Builder
The execution plan is translated into a MongoDB aggregation pipeline. Because MongoDB stores data in flat (denormalized) collections, the query builder simulates relational structure:
- Lookup stages assemble related data across collections
- Match stages apply filter expressions
- Sort stages order results by the requested fields
- Skip and limit stages handle pagination
4. Result Assembler
The raw MongoDB results are reshaped to match the expected GraphQL response structure. Nested relations are assembled into the correct parent-child hierarchy, and field names are mapped to their GraphQL equivalents.
This pipeline runs on every query. What you see in the preview is exactly what external consumers receive from the same endpoint.


Four-stage runtime pipeline: parse → plan → build → assemble.
Query Examples
All queries go to the same endpoint, with an API key of the project (guest projects use their share token — see Integrators):
POST /mock/{slug}/graphql
Authorization: Bearer mck_your_api_keyThe root field is the name of an operation from API design. A list query selects its records inside items and can add total, page and pageSize; a detail query selects the fields directly. The response carries every mapped attribute of the table and its relations — the selection set does not narrow it.
List Query
Fetch a paginated collection of records:
query {
products(page: 1, pageSize: 20) {
items {
id
name
price
category {
id
name
}
}
total
page
pageSize
}
}Detail Query
Fetch a single record by its identifier:
query {
product(id: "abc-123") {
id
name
price
description
category {
id
name
}
}
}Query with Filtering
Pass the parameters the operation defines in API design — here minPrice (on price, gte) and maxPrice (on price, lte):
query {
products(minPrice: 10, maxPrice: 50, pageSize: 10) {
items {
id
name
price
}
total
}
}Query with Sorting
Order results with sortField (an attribute name) and sortDirection:
query {
products(sortField: "price", sortDirection: DESC, pageSize: 10) {
items {
id
name
price
}
total
}
}Query with Nested Relations
Relations of the table come back nested, one level deep:
query {
customers(pageSize: 5) {
items {
id
firstName
lastName
orders {
id
totalAmount
createdAt
}
}
total
}
}Filtering in Detail
Filters belong to the operation: you define them in API design and the runtime applies them on every request. Scope filters are fixed conditions of the operation; parameters are arguments the caller sends — each bound to one attribute and one operator, optionally required or with a default value.
Available Operators
| Operator | Description | Works With |
|---|---|---|
eq | Equals | All types |
neq | Not equals | All types |
gt / gte | Greater than / greater or equal | Numbers, Dates |
lt / lte | Less than / less or equal | Numbers, Dates |
in | One of a list of values | All types |
like | Contains (case-insensitive) | Strings |
notIn | None of a list of values (scope filters only) | All types |
isNull / isNotNull | Is null / is not null (scope filters only) | All types |
Combining Filters
All scope filters and parameters of an operation combine with AND — there is no OR and no nesting at request time. Pass parameter values inline or as GraphQL variables:
query ProductsInRange($min: Float, $max: Float) {
products(minPrice: $min, maxPrice: $max, pageSize: 20) {
items {
id
name
price
}
total
}
}With the variables { "min": 10, "max": 50 }, this returns the products priced from 10 to 50.
Parameter Validation
An argument the operation does not define is refused with BAD_USER_INPUT, and so is a required parameter that is missing and has no default value. Operations without parameters ignore unknown arguments. Define parameters in the API Design view.
Search
searchTerm matches case-insensitively in every attribute marked searchable (up to 64 characters):
query {
products(searchTerm: "oak", pageSize: 10) {
items {
id
name
}
total
}
}Pagination
Mockomat uses page-based pagination:
| Parameter | Description | Default |
|---|---|---|
page | Page number, starting at 1 | 1 |
pageSize | Records per page, at most 100 | The operation's default page size (25 unless changed) |
A typical paginated request:
query {
products(page: 3, pageSize: 20) {
items {
id
name
price
}
total
page
pageSize
}
}This returns records 41–60. total counts every matching record, so the last page is total / pageSize, rounded up.
Sorting
Sort with sortField (an attribute name) and sortDirection:
| Direction | Meaning |
|---|---|
ASC | Ascending (A→Z, 0→9, oldest→newest) |
DESC | Descending (Z→A, 9→0, newest→oldest) |
Only one sort field can be applied per query. Without sortField, the operation's default sort applies; if it has none, results come in storage order.
Relation Traversal
One of the runtime's most powerful features is its ability to simulate relational data from flat MongoDB collections.
How It Works
MongoDB stores data in denormalized collections — each record is a flat document without foreign key joins. The runtime simulates relational structure by:
- Reading the relation definition from your model (source entity, target entity, cardinality).
- Building lookup stages in the MongoDB aggregation pipeline that join related collections.
- Assembling nested results that match the GraphQL response shape.
This means your GraphQL queries behave as if they are running against a fully relational database, even though the underlying storage is document-based.
What to Validate
When testing relation traversal:
- 1:1 relations should return a single nested object (or null if no match).
- 1:n relations should return an array of nested objects.
- Empty relations should return an empty array
[], not null. - Nested relations resolve one level deep: a related record carries its own attributes, not its relations (Customer → Order works; the order's items are not included). Each parent gets at most 50 related records.
Query Behavior Checklist
For each key entity in your model, validate:
- List query stability — does the same query return consistent structure across repeated calls?
- Single-item consistency — does a detail query return all expected fields?
- Null and missing-field behavior — are optional fields correctly represented as null?
- Relation traversal — do nested objects resolve with the correct cardinality?
- Filter accuracy — do filter expressions match the expected subset?
- Sort correctness — does sorting produce a predictable, stable order?
- Pagination boundaries — do
pageandpageSizeproduce clean page slices without duplicates?


Filter, sort, and pagination behavior validation.
Runtime Inspection and Debugging
When behavior looks wrong, inspect in this order. For a comprehensive diagnostic guide covering all common issues and their resolutions, see the Troubleshooting reference.
1. Check Table and Attribute Definitions
The most common cause of unexpected behavior is a misconfigured attribute:
- Is the field type correct? (A price stored as
stringwon't sort numerically.) - For search: is the field marked as Searchable?
- For sorting: is
sortFieldthe name of an attribute bound to a data column? - Does the field have a mapping configured?
2. Check Endpoint and Query Metadata
Verify that the query is configured correctly in the API design view:
- Is the query enabled?
- Are the query name and parameters correct?
- Is the pagination configuration appropriate?
3. Check Source Mapping State
If fields return null or unexpected values:
- Is the mapping type correct (Data Source or Constant)?
- For Data Source mappings, is the attribute bound to the right column of the imported data, and does that column hold values for these records?
- Constant values appear on every row, on rows of imported data and on rows composed from value pools alike.
- Computed mappings: the runtime does not evaluate expressions, so a computed field is not part of the response.
4. Check Relation Policies
If nested data is missing or incorrect:
- Is the relation direction correct (source → target)?
- Is the cardinality right (1:1 vs 1:n)?
- Does the target entity exist and have mapped data?
- Are the linking columns correctly specified?
Common Issues and Resolutions
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Empty response | The table is not bound to imported data (NOT_READY) | Bind the table to imported data in the Mappings pane |
| Fields return null | No mapping configured | Bind the attribute to a column of the imported data (Data Source mapping) |
| Nested relation empty | Relation misconfigured | Verify direction, target entity, and linking columns |
| Sort not working | sortField is not the name of a mapped attribute | Use the name of a mapped attribute |
| Filter returns everything | The operation defines no parameter for that argument | Add the parameter in API design |
| Wrong data types | Mapping type mismatch | Check that mapping produces the expected type |
| Pagination skips items | pageSize changed between requests | Keep pageSize constant and step page by 1 |


Runtime inspection flow and debug checkpoints.
Validation Before Export
Runtime should confirm readiness before you move to backend code generation. A model that passes runtime validation is far more likely to produce a clean, functional generated backend.
Readiness Criteria
Before exporting, confirm that:
- Required fields are stable — all required attributes have consistent, non-null values.
- Operation surface is intentional — only the queries you want to expose are enabled.
- Relation behavior is explainable — every nested query resolves correctly and the cardinality matches your business rules.
- Filter and sort behavior is predictable — consumers can rely on these operations working as documented.
- No unresolved hints — the preview shows no warnings about unmapped attributes or missing configuration.
Pre-Export Validation Workflow
- Run list queries for every entity — check structure and data quality.
- Run detail queries for key entities — check field completeness.
- Test all configured filters — verify correct subsetting.
- Test sorting on the attributes your consumers sort by — verify ordering.
- Test pagination boundaries — verify clean page transitions.
- Test nested relation queries — verify correct assembly at every level.


Pre-export runtime validation summary view.