Skip to content

Default values override "required" state in output types #1776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 of 2 tasks
dave-addition opened this issue Jul 22, 2024 · 2 comments
Closed
1 of 2 tasks

Default values override "required" state in output types #1776

dave-addition opened this issue Jul 22, 2024 · 2 comments
Labels
bug Something isn't working openapi-ts Relevant to the openapi-typescript library

Comments

@dave-addition
Copy link

dave-addition commented Jul 22, 2024

Description

Generated types don't allow undefined inputs on fields with default values, even if they're not part of the "required" fields array.

Name Version
openapi-typescript 7.0.2
Node.js v20.12.2
OS + version macOS 14.5

Reproduction

Create a package.json like:

{
  "name": "test-scripts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "http-server -p 4000",
    "generate": "tsx ./generate-types.ts > ./openapi-output.ts"
  },
  "dependencies": {
    "openapi-typescript": "7.0.2",
    "tsx": "4.7.1",
    "typescript": "5.4.5"
  },
  "devDependencies": {
    "http-server": "14.1.1"
  },
  "author": "",
  "license": "ISC"
}

Add a docs-json file with:

{
  "openapi": "3.0.0",
  "security": [
    {
      "bearer": []
    }
  ],
  "paths": {
    "/do/the/thing": {
      "post": {
        "operationId": "Controller_method",
        "summary": "Do something.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MyInputType"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Did the thing."
          },
          "400": {
            "description": "Bad request."
          }
        }
      }
    }
  },
  "info": {
    "title": "Test API",
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/license/mit"
    },
    "description": "",
    "version": "1.0",
    "contact": {}
  },
  "tags": [],
  "servers": [
    {
      "url": "https://some.site.com/v1"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http"
      }
    },
    "schemas": {
      "MyInputType": {
        "type": "object",
        "properties": {
          "requiredField": {
            "type": "string"
          },
          "optionalField": {
            "type": "string"
          },
          "optionalFieldWithDefault": {
            "type": "string",
            "default": "foo"
          }
        },
        "required": [
          "requiredField"
        ]
      }
    }
  }
}

and a generate-types.ts file with:

import openapiTS from "openapi-typescript";
import ts, { EmitHint } from "typescript";

openapiTS("http://127.0.0.1:4000/docs-json", {
  alphabetize: true,
}).then((output) => {
  const outFile = ts.createSourceFile("API.ts", "", ts.ScriptTarget.Latest);
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
  output.forEach((typeNode) => {
    console.log(printer.printNode(EmitHint.Unspecified, typeNode, outFile));
  });
});

Run yarn start in one terminal window and yarn generate in another. This creates an openapi-output.ts file.

Expected result

I expect a schema which looks like this:

        MyInputType: {
            optionalField?: string;
            /** @default foo */
            optionalFieldWithDefault?: string;
            requiredField: string;
        };

But this is what the script outputs:

        MyInputType: {
            optionalField?: string;
            /** @default foo */
            optionalFieldWithDefault: string;
            requiredField: string;
        };

I'm surprised by this because the "required" array is part of the offical JSON schema spec, whereas the default value is (to the best of my knowledge) not. The closest thing I could find to documentation was here, where the docs say:

Unless stated otherwise, the property definitions follow those of JSON Schema and do not add any additional semantics.

So I would expect the ? types to be determined by "required" fields only.

Checklist

  • My OpenAPI schema passes the Redocly validator (npx @redocly/cli@latest lint)
  • I’m willing to open a PR (see CONTRIBUTING.md) (I may be open to this, but don't want to commit to it as I'm not familiar with this project and unsure how tough it would be)
@dave-addition dave-addition added bug Something isn't working openapi-ts Relevant to the openapi-typescript library labels Jul 22, 2024
@phk422
Copy link
Contributor

phk422 commented Jul 23, 2024

@dave-addition You can refer to this pr:#1746 (comment)

@dave-addition
Copy link
Author

dave-addition commented Jul 23, 2024

Ah! Yeah setting defaultNonNullable to false does indeed fix this. For what it's worth I find this default behavior a bit surprising... but the option is clear and well documented, so works for me!

Thanks to you and all the other contributors for all your hard work on this project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working openapi-ts Relevant to the openapi-typescript library
Projects
None yet
Development

No branches or pull requests

2 participants