ts-spec / tspec

Type-driven API Documentation library. Auto-generating REST API document based on TypeScript types.
https://ts-spec.github.io/tspec/
MIT License
127 stars 5 forks source link

[bug-fix] Generated OAS contains an invalid property #34

Closed skgndi12 closed 1 year ago

skgndi12 commented 1 year ago

Describe bug

When specifying content-type as described in the official document, a property not defined in the OpenAPI Specification called mediaType was added as a subproperty of schema. As a result, an invalid OAS was created.

스크린샷 2023-08-06 오후 3 10 40

To reproduce

Condition

  1. Version: 0.1.104
  2. Situation: When specifying content-type with the @mediaType tag above the request body type

Schema and request body type

// schema
export type DevApiSpec = Tspec.DefineApiSpec<{
  basePath: '/api/v1/dev';
  security: 'jwt';
  tags: ['Development'];
  paths: {
    '/greeting': {
      post: {
        summary: 'Greeting',
        body: GreetingV1Request,
        responses: {
          200: GreetingV1Response,
          default: HttpErrorResponse,
        };
      };
    };
  };
}>;

// Request body type
/** @mediaType application/x-www-form-urlencoded */
export interface GreetingV1Request {
  message: string;
}

Generated OAS

{
  "info": {
    "title": "Mr.C API",
    "version": "1.0.0"
  },
  "openapi": "3.0.3",
  "paths": {
    "/api/v1/dev/greeting": {
      "post": {
        "operationId": "DevApiSpec_post_/greeting",
        "tags": [
          "Development"
        ],
        "summary": "Greeting",
        "security": [
          {
            "jwt": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "mediaType": "application/x-www-form-urlencoded",
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string"
                  }
                },
                "additionalProperties": false,
                "required": [
                  "message"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GreetingV1Response"
                }
              }
            }
          },
          "default": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/healthz/liveness": {
      "get": {
        "operationId": "HealthApiSpec_get_/liveness",
        "tags": [
          "Health Checks"
        ],
        "summary": "Check for liveness",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LivenessResponse"
                }
              }
            }
          },
          "default": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "GreetingV1Response": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "HttpErrorResponse": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/ErrorType"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false,
        "required": [
          "messages",
          "type"
        ]
      },
      "ErrorType": {
        "enum": [
          "BAD_REQUEST",
          "COMMENT_NOT_FOUND",
          "FORBIDDEN",
          "METHOD_NOT_ALLOWED",
          "NOT_ACCEPTABLE",
          "PAYLOAD_TOO_LARGE",
          "REPLY_NOT_FOUND",
          "REVIEW_NOT_FOUND",
          "ROUTE_NOT_FOUND",
          "UNAUTHORIZED",
          "UNEXPECTED",
          "UNSUPPORTED_MEDIA_TYPE",
          "USER_NOT_FOUND"
        ],
        "type": "string"
      },
      "GreetingV1Request": {
        "mediaType": "application/x-www-form-urlencoded",
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "additionalProperties": false,
        "required": [
          "message"
        ]
      },
      "LivenessResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "additionalProperties": false,
        "required": [
          "message"
        ]
      }
    },
    "securitySchemes": {
      "jwt": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  }
}

Changes

In the openapiGenerator file, notice that the value of bodyParams is assigned with mediaType included. Modified bodyParams to not include the value by creating and assigning a separate variable called mediaType. I wanted to test this fix, but I couldn't find a test code. Please review if you find any issues.

hyeonss0417 commented 1 year ago

I update tspec version to 0.1.105 including your changes. 🎉

https://github.com/ts-spec/tspec/releases/tag/v0.1.105