Skip to content

TypeScript target: request types require readOnly properties #43

Open

Description

@SeanSanker

With --target ts, a request body whose schema has required readOnly properties keeps them required in the request type. Callers have to supply server-assigned values such as id and created_on, or cast, and whatever they pass is sent.

src/lib.rs says "The body keeps its read-only fields, since a model is the same object in requests and responses: a generator leaves out of what a client sends the fields that [Field::is_read_only] reports" (likewise src/types.rs), but nothing under src/bin/forge checks is_read_only. OpenAPI 3.0 also says a required readOnly property is required in responses only.

Repro

On main at 697d90e:

{
  "openapi": "3.0.3",
  "info": { "title": "Repro", "version": "1" },
  "servers": [{ "url": "https://api.example.com" }],
  "paths": {
    "/things": {
      "post": {
        "x-fern-sdk-group-name": "things", "x-fern-sdk-method-name": "create",
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/Thing" } } } },
        "responses": { "200": { "description": "ok", "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/Thing" } } } } }
      }
    }
  },
  "components": { "schemas": { "Thing": {
    "type": "object", "required": ["id", "createdOn", "name"],
    "properties": {
      "id": { "type": "string", "readOnly": true },
      "createdOn": { "type": "string", "format": "date-time", "readOnly": true },
      "name": { "type": "string" }
    } } } }
}
forge spec.json --target ts --out sdk

sdk/things/client.ts has export type CreateRequest = Thing;, and sdk/things/models.ts has:

export interface Thing {
  createdOn: Temporal.Instant;
  id: string;
  name: string;
}

So create({ name: "x" }) doesn't type-check.

Impact

In openapi.forge.json from this repo's openapi@416bb87 release, 40 JSON request bodies require a readOnly property at the top level (counting allOf), and at least 9 more do so only in a nested object, such as policies[].id in POST /accounts/{account_id}/tokens. For example, POST /accounts/{account_id}/workers/scripts/{script_name}/deployments uses workers_deployment, which requires the read-only id, source and created_on.

A few look like mistakes in the document instead. For example, POST /accounts/{account_id}/teamnet/routes requires tunnel_id, which is marked read-only through the shared tunnel_tunnel_id schema but has to be sent. Leaving read-only fields out of what's sent would break that call until the document is fixed.

Expected

Read-only properties are left out of request types, or at least not required, as src/lib.rs describes. Since models are shared, this probably needs request-side types for models with read-only fields, nested ones included.

Found while experimenting with an alternative TypeScript generator on top of forge.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions