openapi-interfaces 0.4.0

Generate OpenAPI schemas for related GET, POST, PUT and JSON Merge Patch types
# `openapi-interfaces`: Automatically generate `GET`, `POST`, `PUT` and JSON Merge Patch schemas for OpenAPI

**EXPERIMENTAL.** Details subject to change.

This tool extends [OpenAPI 3.1.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md) with the ability to generate related schemas automatically. Specifically, you can define a single interface type `Widget`, and automatically generate:

- `Widget` (for `GET` requests)
- `WidgetPost`
- `WidgetPut`
- `WidgetMergePatch` (for `PATCH` requests using [JSON Merge Patch]https://datatracker.ietf.org/doc/html/rfc7396 format, which is basically a nicely formalized "partial `PUT`")

## Installation

To install the latest version, first make sure you have a Rust toolchain. You
can [install one using these instructions](https://rustup.rs/). Then run:

```sh
cargo install -f openapi-interfaces
```

We will provide binaries at some point.

## Usage

```sh
openapi-interfaces --help
openapi-interfaces api_with_interfaces.yml -o api.yml
```

## OpenAPI extensions

This tool defines a new `components.interfaces` section, which allows specifying "interface" types. For example:

```yaml
components:
  # You can declare schemas normally if you wish.
  schemas: {}

  # But we also support interface definitions.
  interfaces:
    Resource:
      emit: false # Do not include this in generated output.
      members:
        id:
          required: true
          schema:
            # Normal OpenAPI / JSON Schema definitions.
            type: string
            format: uuid
    Widget:
      # Include all fields from `Resource`.
      $includes: "Resource"
      members:
        # We can override properties from `Resource` using JSON
        # Merge Patch syntax.
        id:
          schema:
            example: e35a3c8d-5486-49ec-9b23-6747afc19570
        name:
          required: true
          mutable: true
          schema:
            type: string
        comment:
          mutable: true
          schema:
            type: string
        readonly:
          required: true
          # This can't be updated once the object is created.
          mutable: false
          # But we do allow this to be set at creation time.
          # If omitted, `initializable` defaults to the value
          # of the `mutable` option.
          initializable: true
          schema:
            type: string
```

This will automatically generate four `Widget` types:

```yaml
components:
  schemas:
    Widget: ...
    WidgetPost: ...
    WidgetPut: ...
    WidgetMergePatch: ...
```

For the complete definitions, see [`example_output.yml`](./examples/example_output.yml).

### Referring to interfaces

We can then refer to interfaces using the new `$interface` key, with an appropriate variant:

```yaml
paths:
  /widgets:
    post:
      requestBody:
        required: true
        content:
          application/json:
              schema:
                # This becomes `$ref: "#/components/schemas/WidgetPost`.
                $interface: "Widget#Post"
      responses:
        201:
          content:
            application/json:
              schema:
                # This becomes `$ref: "#/components/schemas/Widget`.
                $interface: "Widget"
```

Possible options are:

- `Widget`: The type returned by `GET` and other methods that provide a complete resource from the server.
- `Widget#Post`: The type passed to a `POST` request.
- `Widget#Put`: The type passed to a `PUT` request. May also be used as the base type for applying `#MergePatch` values.
- `Widget#MergePatch`: A [JSON Merge Patch]https://datatracker.ietf.org/doc/html/rfc7396 schema that can be passed to `PATCH`.
- `Widget#SameAsInterface`: **May only be used inside `components.interfaces`.** This is a shortcut value that says "When generating a `#Get` interface, include `$ref: "components.schemas.Widget`. When generating a `#Post` interface, include `$ref: "components.schemas.WidgetPost`." In other words, use the same variant selector as the containing interface. Useful for when compound types are sent over the wire.