rspec-openapi icon indicating copy to clipboard operation
rspec-openapi copied to clipboard

RFC: Update shared schemas in /components/schemas section

Open exoego opened this issue 2 years ago • 1 comments

Summary

When rspec-openapi detects $ref in the existing item to be modified, rspec-openapi update the referenced item in components section.

Basic example

Let's say we have the openapi below, generated with rspec-openapi and modified manually to use $ref.

  "/tables":
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/Table"
              example:
              - (snip)
  "/tables/{id}":
    get:
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
        example: 1
      responses:
        '200':
          content:
             "$ref": "#/components/schemas/Table"
components:
  schemas:
      Table:
        type: object
        properties:
          id:
            type: integer
          name:
            type: string

If the implementation added a new field storage_size, Table in the #/components/schemas/ get updates.

Motivation

If there are "duplicated" schemas, such as Table in get /tables, post /tables andget /tables/{id}, some OpenAPI client generators generate separate types for each of duplicated schemas. One example is openapi-typescript-codegen generating API client codes like below:

    public static getTables( ..snip.. ): CancelablePromise<Array<{
        id?: number;
        name?: string;
        description?: string;
        database?: {
            id?: number;
            name?: string;
        };
        ..snip..
    }>> {..snip..}

    public static postTables(..snip..): CancelablePromise<{
        id?: number;
        name?: string;
        description?: string;
        database?: {
            id?: number;
            name?: string;
        };
        ..snip..
    }> {..snip..}

    public static getTables1(id: number): CancelablePromise<{
        id?: number;
        name?: string;
        description?: string;
        database?: {
            id?: number;
            name?: string;
        };
        ..snip..
    }> {..snip.. }

In this example, there are three unnamed structural types that represent Table. Those three types have the exact same type and are "compatible" if the type system at the client-side supports structural typing. TypeScript does, but Java not.

There is another problem. Since those types have no name, it is a bit tricky to refer the types in a nominal manner. (One may use ReturnType<func> and other utility types).

Users may reduce duplications by manually lifting the schemas into /components/schemas/Table and using $refs with it. However, /components/schemas/Table are not updated by rspec-openapi. Users need to update /components/schemas/ by themselves, which diminishes the value of rspec-openapi somewhat.

If the schema in /components/schemas gets updated automatically, it helps leverage OpenAPI files with client-generating tools with strong types.

Related issues

  • https://github.com/k0kubun/rspec-openapi/issues/50

exoego avatar Jul 29 '22 07:07 exoego

The feature looks good to me. While it's hard for rspec-openapi to generate $ref by itself because of its design, when a human decides to carve out a $ref manually, it makes total sense to let rspec-openapi update it. I still have no good idea to fully automate it, but it seems like a good first step towards better $ref support.

It's a nitpick, but I guess this issue should be formatted like s/Summary/Proposal/ to make your point clear.

k0kubun avatar Jul 29 '22 17:07 k0kubun