Skip to content

read-write-markers + root-types Generated types with read markers can't be used with openapi-fetch #2726

Description

@Tri125

openapi-typescript version

Unreleased v7.14.0 (commit: b04ec75)

Node.js version

24.12.0

OS + version

Windows 11

Description

The root types generated with read-write-markers and root-types can't really be used when interacting with openapi-fetch.

The schema won't be assignable to data when obtaining results from a GET.

Additionally, the schema won't be assignable to body when POSTing the data.

import createClient from "openapi-fetch";
import type { paths, SchemaPet } from "./openapi/openapi.js"; // generated by openapi-typescript

const client = createClient<paths>({ baseUrl: "http://localhost:3030/" });

const {data, error} = await client.GET("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    }
})

if (data) {
    /*
    Types of property 'id' are incompatible.
    Type 'number' is not assignable to type '$Read<number>'.ts
   */
    const myCurrentPet: SchemaPet = data;
}

const myNewPet : SchemaPet = {
    // Forced to set the readOnly prop even though my intent is to POST it.
    id: {
        $read: 235
    },
    name: "Mittens",
    tag: "cat"
}

await client.POST("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    },
    body: {
    /*
   Type '{ id: $Read<number>; name: string; tag?: string; }' is not assignable to type '{ id?: undefined; }'.
   */
        ...myNewPet
    }
})

Reproduction

I'm using the currently unreleased version commit: b04ec75.

# redocly.yaml
extends:
  - recommended

apis:
  core@v2:
    root: ./openapi.yaml
    x-openapi-ts:
      output: ./src/openapi/openapi.d.ts
      read-write-markers: true
      root-types: true
# openapi.yaml
openapi: 3.0.0
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
    url: https://test.test
servers:
  - url: http://localhost:3030
security: []
paths:
  /pets/{petId}:
    post:
      summary: Create a pet
      operationId: createPets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      tags:
        - pets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Pet:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
        name:
          type: string
        tag:
          type: string
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string
// index.ts

import createClient from "openapi-fetch";
import type { paths, SchemaPet } from "./openapi/openapi.js"; // generated by openapi-typescript

const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });

const {data, error} = await client.GET("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    }
})

if (data) {
    const myCurrentPet : SchemaPet = data;
}

const myNewPet : SchemaPet = {
    id: {
        $read: 235
    },
    name: "Mittens",
    tag: "cat"
}

await client.POST("/pets/{petId}", {
    params: {
        path: {
            petId: "234"
        }
    },
    body: {
        ...myNewPet
    }
})

Expected result

I expected to be able to directly use the typing when interacting with openapi-fetch.

Perhaps there should be one generated schema type for readOnly and a second generated schema type for writeOnly?

Required

  • My OpenAPI schema is valid and passes the Redocly validator (npx @redocly/cli@latest lint)

Extra

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingopenapi-tsRelevant to the openapi-typescript library

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions