OpenAPI alternative for type-safe code generation

4 min read Original article ↗

Simple API

A simple GET endpoint which returns a hello world message.

{
  "operations": {
    "getMessage": {
      "description": "Returns a hello world message",
      "method": "GET",
      "path": "/hello/world",
      "return": {
        "schema": {
          "type": "reference",
          "target": "Hello_World"
        }
      }
    }
  },
  "definitions": {
    "Hello_World": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    }
  }
}
const client = new Client()
client.getMessage(): HelloWorld

interface HelloWorld {
    message?: string
}

Argument Query

Through the arguments keyword you can map values from the HTTP request to an argument, in this example we map the HTTP query parameters to the startIndex and count argument

{
  "operations": {
    "getAll": {
      "description": "Returns available todo entries",
      "method": "GET",
      "path": "/todo",
      "arguments": {
        "startIndex": {
          "in": "query",
          "schema": {
            "type": "integer"
          }
        },
        "count": {
          "in": "query",
          "schema": {
            "type": "integer"
          }
        }
      },
      "return": {
        "schema": {
          "type": "reference",
          "target": "Todos"
        }
      }
    }
  },
  "definitions": {
    "Todos": {
      "type": "object",
      "properties": {
        "entries": {
          "type": "array",
          "schema": {
            "type": "reference",
            "target": "Todo"
          }
        }
      }
    },
    "Todo": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string"
        }
      }
    }
  }
}
const client = new Client()
client.getAll(startIndex: number, count: number): Todos

interface Todo {
    title?: string
}



interface Todos {
    entries?: Array<Todo>
}

Argument Body

In this example we map the HTTP request body to the payload argument

{
  "operations": {
    "create": {
      "description": "Inserts a new todo entry",
      "method": "POST",
      "path": "/todo",
      "arguments": {
        "payload": {
          "in": "body",
          "schema": {
            "type": "reference",
            "target": "Todo"
          }
        }
      },
      "return": {
        "schema": {
          "type": "reference",
          "target": "Message"
        }
      }
    }
  },
  "definitions": {
    "Todo": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string"
        }
      }
    },
    "Message": {
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean"
        },
        "message": {
          "type": "string"
        }
      }
    }
  }
}
const client = new Client()
client.create(payload: Todo): Message

interface Message {
    success?: boolean
    message?: string
}

interface Todo {
    title?: string
}

Throws

Through the throws keyword you can define specific error payloads, the generated client will then also throw an exception in case the server returns such an error code

{
  "operations": {
    "getMessage": {
      "description": "Returns a hello world message",
      "method": "GET",
      "path": "/hello/world",
      "return": {
        "schema": {
          "type": "reference",
          "target": "Hello_World"
        }
      },
      "throws": [{
        "code": 500,
        "schema": {
          "type": "reference",
          "target": "Error"
        }
      }]
    }
  },
  "definitions": {
    "Hello_World": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    },
    "Error": {
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean"
        },
        "message": {
          "type": "string"
        }
      }
    }
  }
}
const client = new Client()
client.getMessage(): HelloWorld throws Error

interface Error {
    success?: boolean
    message?: string
}

interface HelloWorld {
    message?: string
}

Operation group

Through the dot notation at the operation key you can group your operations into logical units

{
  "operations": {
    "todo.create": {
      "description": "Inserts a new todo entry",
      "method": "POST",
      "path": "/todo",
      "arguments": {
        "payload": {
          "in": "body",
          "schema": {
            "type": "reference",
            "target": "Todo"
          }
        }
      },
      "return": {
        "schema": {
          "type": "reference",
          "target": "Message"
        }
      }
    },
    "product.create": {
      "description": "Inserts a new product",
      "method": "POST",
      "path": "/product",
      "arguments": {
        "payload": {
          "in": "body",
          "schema": {
            "type": "reference",
            "target": "Product"
          }
        }
      },
      "return": {
        "schema": {
          "type": "reference",
          "target": "Message"
        }
      }
    }
  },
  "definitions": {
    "Todo": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string"
        }
      }
    },
    "Product": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string"
        }
      }
    },
    "Message": {
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean"
        },
        "message": {
          "type": "string"
        }
      }
    }
  }
}
const client = new Client()
client.todo().create(payload: Todo): Message
client.product().create(payload: Product): Message

interface Message {
    success?: boolean
    message?: string
}

interface Product {
    title?: string
}

interface Todo {
    title?: string
}