Specification

This document describes the TypeAPI specification. The TypeAPI specification defines a JSON format to describe REST APIs for type-safe code generation.



Goals

Non-Goals

Reasoning

For a long time the OpenAPI community was divided into two communities, one building documentation tools and the other trying to build code generation tools. Building documentation tools has very different requirements than building code generation tools. For a documentation tool you can simply render and show all defined endpoints and constraints, a code generation tool on the other side needs to understand the structure and relations of your model.

The OpenAPI specification has moved more and more to the documentation community by directly integrating JSON Schema into the specification. The problem with JSON Schema and code generation is, that JSON Schema is a constraint system, based on such constraints it is very difficult or impossible to build a clean code generator since the constraints only define what is not allowed. For a code generator you like to have a schema which explicit models your data structure.

With TypeAPI we want build a new home for the code generation community. Conceptual the main difference is that with OpenAPI you describe routes and all aspects of a route, at TypeAPI we describe operations, an operation has arguments and those arguments are mapped to values from the HTTP request. Every operation returns a response and can throw exceptions which are also mapped to an HTTP response. An operation basically represents a method or function in a programming language. This approach makes it really easy to generate complete type safe code.


Schema

Every TypeAPI has a Root definition. The Root must contain at least the operations and definitions keyword i.e.:

{
    "operations": {
        "getMessage": { ... },
    },
    "definitions": {
        "TypeA": { ... },
        "TypeB": { ... }
    }
}

Operations

The operations keyword contains a map containing Operation objects. The key represents the identifier of this operation, through the dot notation i.e. user.getMessage you can group your operations into logical units.

{
    "operations": {
        "getMessage": {
            "description": "Returns a hello world message",
            "method": "GET",
            "path": "/hello/world",
            "return": {
                "schema": {
                    "$ref": "Hello_World"
                }
            }
        }
    },
    "definitions": {
        "Hello_World": {
            "type": "object",
            "properties": {
                "message": {
                    "type": "string"
                }
            }
        }
    }
}

Return

Every operation can define a return type. In the above example the operation simply returns a Hello_World object.


Arguments

Through arguments keywords you can map values from the HTTP request to specific method arguments. In the following example we have an argument status which maps to a query parameter and an argument payload which contains the request payload.

{
    "operations": {
        "insertMessage": {
            "description": "Inserts and returns a hello world message",
            "method": "POST",
            "path": "/hello/world",
            "arguments": {
                "status": {
                    "in": "query",
                    "schema": {
                        "type": "integer"
                    }
                },
                "payload": {
                    "in": "body",
                    "schema": {
                        "$ref": "Hello_World"
                    }
                }
            },
            "return": {
                "schema": {
                    "$ref": "Hello_World"
                }
            }
        }
    },
    "definitions": {
        "Hello_World": {
            "type": "object",
            "properties": {
                "message": {
                    "type": "string"
                }
            }
        }
    }
}

This would map to the following HTTP request.

POST https://api.acme.com/hello/world?status=2
Content-Type: application/json

{
  "message": "Hello"
}

Throws

Besides the return type an operation can return multiple exceptional states in case an error occurred. Every exceptional state is then mapped to a specific status code i.e. 404 or 500. The generated client SDK will then throw a fitting exception containing the JSON payload in case the server returns such an error response code. The client will either return the success response or throw an exception. This greatly simplifies error handling at your client code.

{
    "operations": {
        "getMessage": {
            "description": "Returns a hello world message",
            "method": "POST",
            "path": "/hello/world",
            "return": {
                "schema": {
                    "$ref": "Hello_World"
                }
            },
            "throws": [{
                "code": 404,
                "schema": {
                    "$ref": "Error"
                }
            }, {
                "code": 500,
                "schema": {
                    "$ref": "Error"
                }
            }]
        }
    },
    "definitions": {
        "Hello_World": {
            "type": "object",
            "properties": {
                "message": {
                    "type": "string"
                }
            }
        },
        "Error": {
            "type": "object",
            "properties": {
                "message": {
                    "type": "string"
                }
            }
        }
    }
}

Definitions

The definitions keyword maps to the TypeSchema specification and represents a map containing Struct, Map and Reference types. Those types are then used to describe incoming and outgoing JSON payloads.


Edit this page