document may be a parsed JSON object, or a raw YAML/JSON string (parsed with js-yaml, which accepts plain JSON text too - so no separate "format" field is needed). Import is additive only: it never modifies or removes an existing type or route, and a name/routeName/path collision with something that already exists is reported as skipped, not overwritten. It also never generates template data or creates relationships automatically - review and complete the configuration afterward via the normal Types/Relationships/Routes endpoints. Malformed documents (not an object, or not valid YAML/JSON) return 422.
Request
{
"document": {
"openapi": "3.0.0",
"info": {
"title": "Sample Blog API",
"version": "1.0.0"
},
"components": {
"schemas": {
"User": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer"
},
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
}
}
},
"Post": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer"
},
"userId": {
"type": "integer"
},
"title": {
"type": "string"
}
}
},
"Widget": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
},
"paths": {
"/users": {
"get": {},
"post": {}
},
"/users/{id}": {
"get": {},
"put": {}
},
"/users/{id}/posts": {
"get": {}
},
"/widgets": {
"get": {}
}
}
}
}
Response (200)
{
"typesCreated": [
"User",
"Post"
],
"typesSkipped": [
{
"name": "Widget",
"reason": "no \"id\" property found to use as an unambiguous identifierField"
}
],
"routesCreated": [
{
"id": 1,
"method": "GET",
"path": "/users",
"typeId": 1
},
{
"id": 2,
"method": "POST",
"path": "/users",
"typeId": 1
},
{
"id": 3,
"method": "GET",
"path": "/users/{id}",
"typeId": 1,
"lookupField": "id"
},
{
"id": 4,
"method": "PUT",
"path": "/users/{id}",
"typeId": 1,
"lookupField": "id"
}
],
"routesSkipped": [
{
"method": "GET",
"path": "/users/{id}/posts",
"reason": "nested route requires an existing relationship from \"Post\" to a type with routeName \"users\" - create the relationship first, then add this route manually"
},
{
"method": "GET",
"path": "/widgets",
"reason": "no data type has routeName \"widgets\""
}
]
}
| Supported | Skipped, with a reason |
|---|---|
|
|
Every created type gets a fixed generation.recordCount of 10 and no configured uniqueFields beyond its identifier - OpenAPI has no equivalent concept for either, so these are safe, adjustable defaults rather than a guess at the "right" value. routeName is derived from the schema name pluralized ("User" → "users") since OpenAPI schema names are conventionally singular while the paths that reference them are conventionally plural collections - a schema name this heuristic can't turn into a valid routeName is skipped.
Each paths entry's template must already match one of the four path shapes this service supports (see Mock Routes docs) - OpenAPI's own {param} syntax is identical, so most well-formed documents need no rewriting. For each method on a path:
- The path's own collection segment (the first segment, or the third for a nested path) is matched against a data type's
routeName- no match, no route (routesSkipped). - A path ending in a
{param}getslookupFieldset to the resolved type'sidentifierField- the importer doesn't try to match the param's own name against a specific field. - A nested path (
/parent/{id}/children) requires an existing relationship from the child type to a type whoserouteNameequals the parent segment. OpenAPI documents have no native relationship concept, so a nested path almost always gets skipped on a first import into an empty Project - this is expected, not a bug. Create the relationship (Relationships docs), then re-run the import (or add the route manually) to pick it up, exactly as demonstrated by the second/third requests in.http/admin/openapi-import.http. - A method/path combination that already exists as a route in this Project is reported as a collision, not duplicated.