CreateAPI / CreateAPI

Delightful code generator for OpenAPI specs
MIT License
393 stars 31 forks source link

Failure when empty enum is found #55

Open AvdLee opened 1 year ago

AvdLee commented 1 year ago

See the following output:

avanderlee@Antoines-MBP-2 OpenAPI % create-api generate app_store_connect_api_2.0_openapi.json --module "AppStoreConnect_Swift_SDK" --output . --config .create-api.yml -s
Generating code for app_store_connect_api_2.0_openapi.json...
WARNING: Unknown body content types: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.other("application/a-gzip"), warnings: [], parameters: [:])], defaulting to Data. Use paths.overridenBodyTypes to add support for your content types.
WARNING: Unknown body content types: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.other("application/a-gzip"), warnings: [], parameters: [:])], defaulting to Data. Use paths.overridenBodyTypes to add support for your content types.
WARNING: Unknown body content types: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.other("application/vnd.apple.xcode-metrics+json"), warnings: [], parameters: [:])], defaulting to Data. Use paths.overridenBodyTypes to add support for your content types.
WARNING: Unknown body content types: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.other("application/vnd.apple.xcode-metrics+json"), warnings: [], parameters: [:])], defaulting to Data. Use paths.overridenBodyTypes to add support for your content types.
WARNING: Unknown body content types: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.other("application/vnd.apple.diagnostic-logs+json"), warnings: [], parameters: [:])], defaulting to Data. Use paths.overridenBodyTypes to add support for your content types.
Error: Failed to generate get for Operation(tags: Optional(["SubscriptionOfferCodeOneTimeUseCodes"]), summary: nil, description: nil, externalDocs: nil, operationId: Optional("subscriptionOfferCodeOneTimeUseCodes-get_instance"), parameters: [Either(Parameter(name: "fields[subscriptionOfferCodeOneTimeUseCodes]", context: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.Context.query(required: false, allowEmptyValue: false), description: Optional("the fields to include for returned resources of type subscriptionOfferCodeOneTimeUseCodes"), deprecated: false, schemaOrContent: Either(SchemaContext(style: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.SchemaContext.Style.form, explode: false, allowReserved: false, schema: Either(JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.array(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.ArrayFormat>(format: OpenAPIKit30.JSONTypeFormat.ArrayFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: nil, defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.ArrayContext(items: Optional(OpenAPIKit30.JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.string(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.StringFormat>(format: OpenAPIKit30.JSONTypeFormat.StringFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: Optional([AnyCodable("active"), AnyCodable("createdDate"), AnyCodable("expirationDate"), AnyCodable("numberOfCodes"), AnyCodable("offerCode"), AnyCodable("values")]), defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.StringContext(maxLength: nil, _minLength: nil, pattern: nil)))), maxItems: nil, _minItems: nil, _uniqueItems: nil)))), example: nil, examples: nil)), vendorExtensions: [:])), Either(Parameter(name: "include", context: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.Context.query(required: false, allowEmptyValue: false), description: Optional("comma-separated list of relationships to include"), deprecated: false, schemaOrContent: Either(SchemaContext(style: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.SchemaContext.Style.form, explode: false, allowReserved: false, schema: Either(JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.array(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.ArrayFormat>(format: OpenAPIKit30.JSONTypeFormat.ArrayFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: nil, defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.ArrayContext(items: Optional(OpenAPIKit30.JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.string(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.StringFormat>(format: OpenAPIKit30.JSONTypeFormat.StringFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: Optional([AnyCodable("offerCode")]), defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.StringContext(maxLength: nil, _minLength: nil, pattern: nil)))), maxItems: nil, _minItems: nil, _uniqueItems: nil)))), example: nil, examples: nil)), vendorExtensions: [:])), Either(Parameter(name: "fields[subscriptionOfferCodeOneTimeUseCodeValues]", context: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.Context.query(required: false, allowEmptyValue: false), description: Optional("the fields to include for returned resources of type subscriptionOfferCodeOneTimeUseCodeValues"), deprecated: false, schemaOrContent: Either(SchemaContext(style: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.SchemaContext.Style.form, explode: false, allowReserved: false, schema: Either(JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.array(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.ArrayFormat>(format: OpenAPIKit30.JSONTypeFormat.ArrayFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: nil, defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.ArrayContext(items: Optional(OpenAPIKit30.JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.string(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.StringFormat>(format: OpenAPIKit30.JSONTypeFormat.StringFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: Optional([]), defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.StringContext(maxLength: nil, _minLength: nil, pattern: nil)))), maxItems: nil, _minItems: nil, _uniqueItems: nil)))), example: nil, examples: nil)), vendorExtensions: [:]))], requestBody: nil, responses: OpenAPIKitCore.OrderedDictionary<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response>, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response>>(orderedKeys: [(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 400)), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 403)), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 404)), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 200))], unorderedHash: [(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 400)): Either(Response(description: "Parameter error(s)", headers: nil, content: OpenAPIKitCore.OrderedDictionary<OpenAPIKitCore.OpenAPI.ContentType, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content>(orderedKeys: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:])], unorderedHash: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:]): (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content(schema: Optional(Either(internal(#/components/schemas/ErrorResponse))), example: nil, examples: nil, encoding: nil, vendorExtensions: [:])], _warnings: []), links: OpenAPIKitCore.OrderedDictionary<Swift.String, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>>(orderedKeys: [], unorderedHash: [:], _warnings: []), vendorExtensions: [:])), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 403)): Either(Response(description: "Forbidden error", headers: nil, content: OpenAPIKitCore.OrderedDictionary<OpenAPIKitCore.OpenAPI.ContentType, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content>(orderedKeys: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:])], unorderedHash: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:]): (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content(schema: Optional(Either(internal(#/components/schemas/ErrorResponse))), example: nil, examples: nil, encoding: nil, vendorExtensions: [:])], _warnings: []), links: OpenAPIKitCore.OrderedDictionary<Swift.String, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>>(orderedKeys: [], unorderedHash: [:], _warnings: []), vendorExtensions: [:])), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 404)): Either(Response(description: "Not found error", headers: nil, content: OpenAPIKitCore.OrderedDictionary<OpenAPIKitCore.OpenAPI.ContentType, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content>(orderedKeys: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:])], unorderedHash: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:]): (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content(schema: Optional(Either(internal(#/components/schemas/ErrorResponse))), example: nil, examples: nil, encoding: nil, vendorExtensions: [:])], _warnings: []), links: OpenAPIKitCore.OrderedDictionary<Swift.String, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>>(orderedKeys: [], unorderedHash: [:], _warnings: []), vendorExtensions: [:])), (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode(warnings: [], value: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Response.StatusCode.Code.status(code: 200)): Either(Response(description: "Single SubscriptionOfferCodeOneTimeUseCode", headers: nil, content: OpenAPIKitCore.OrderedDictionary<OpenAPIKitCore.OpenAPI.ContentType, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content>(orderedKeys: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:])], unorderedHash: [OpenAPIKitCore.OpenAPI.ContentType(underlyingType: OpenAPIKitCore.OpenAPI.ContentType.Builtin.json, warnings: [], parameters: [:]): (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Content(schema: Optional(Either(internal(#/components/schemas/SubscriptionOfferCodeOneTimeUseCodeResponse))), example: nil, examples: nil, encoding: nil, vendorExtensions: [:])], _warnings: []), links: OpenAPIKitCore.OrderedDictionary<Swift.String, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Link>>(orderedKeys: [], unorderedHash: [:], _warnings: []), vendorExtensions: [:]))], _warnings: []), callbacks: OpenAPIKitCore.OrderedDictionary<Swift.String, OpenAPIKitCore.Either<OpenAPIKit30.JSONReference<OpenAPIKitCore.OrderedDictionary<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.CallbackURL, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.PathItem>>, OpenAPIKitCore.OrderedDictionary<(extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.CallbackURL, (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.PathItem>>>(orderedKeys: [], unorderedHash: [:], _warnings: []), deprecated: false, security: nil, servers: nil, vendorExtensions: [:]). Failed to generate query parameter Parameter(name: "fields[subscriptionOfferCodeOneTimeUseCodeValues]", context: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.Context.query(required: false, allowEmptyValue: false), description: Optional("the fields to include for returned resources of type subscriptionOfferCodeOneTimeUseCodeValues"), deprecated: false, schemaOrContent: Either(SchemaContext(style: (extension in OpenAPIKit30):OpenAPIKitCore.OpenAPI.Parameter.SchemaContext.Style.form, explode: false, allowReserved: false, schema: Either(JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.array(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.ArrayFormat>(format: OpenAPIKit30.JSONTypeFormat.ArrayFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: nil, defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.ArrayContext(items: Optional(OpenAPIKit30.JSONSchema(warnings: [], value: OpenAPIKit30.JSONSchema.Schema.string(OpenAPIKit30.JSONSchema.CoreContext<OpenAPIKit30.JSONTypeFormat.StringFormat>(format: OpenAPIKit30.JSONTypeFormat.StringFormat.generic, required: true, _nullable: nil, _permissions: nil, _deprecated: nil, title: nil, description: nil, externalDocs: nil, discriminator: nil, allowedValues: Optional([]), defaultValue: nil, example: nil), OpenAPIKit30.JSONSchema.StringContext(maxLength: nil, _minLength: nil, pattern: nil)))), maxItems: nil, _minItems: nil, _uniqueItems: nil)))), example: nil, examples: nil)), vendorExtensions: [:]). Enum "FieldsSubscriptionOfferCodeOneTimeUseCodeValues" has no values

Mostly due to:

Enum "FieldsSubscriptionOfferCodeOneTimeUseCodeValues" has no values

The specification used can be found here

liamnichols commented 1 year ago

Hmm this is interesting because an enum with no values is not compliant with the OpenAPI 3.0 specification. I had a quick scan and can't find an explanation as to why in writing, but when loading the schema into VSCode with the OpenAPI plugin, it also alerts me to the issue:

Screenshot 2022-07-12 at 10 52 58

That's because the specifications schema defines enum with minItems of 1:

https://github.com/OAI/OpenAPI-Specification/blob/aa91a19c43f8a12c02efa42d64794e396473f3b1/schemas/v3.0/schema.json#L403-L409

I wonder what the expected outcome is when having no items, because presumably you cannot decode any value into an empty enum?

In fact, it doesn't seem possible to conform to Codable when there are no cases:

Screenshot 2022-07-12 at 10 59 52

I guess the option here might be to patch the schema manually to remove that case, while filing a bug report with Apple? ๐Ÿ™ˆ

In the meantime, you might be able to unblock yourself by using the --allow-errors option, but I've never used it before so I'm not sure if it will bypass this kind of error or not... Let me know how you get on though!

liamnichols commented 1 year ago

I found the docs for the endpoint that uses this enum:

https://developer.apple.com/documentation/appstoreconnectapi/read_one-time_use_offer_code_information

It seems that fields[subscriptionOfferCodeOneTimeUseCodeValues] is documented as a plain string, and not an enum:

Screenshot 2022-07-12 at 11 25 41

It could be that other tools consider an empty enum as just a regular string.. Which I guess we could implement if it does come to it, but first its probably worth trying to get the schema fixed upstream to match the documentation

liamnichols commented 1 year ago

I raised FB10631712

fields[subscriptionOfferCodeOneTimeUseCodeValues] parameter of v1/subscriptionOfferCodeOneTimeUseCodes/{id} is incorrectly defined as an empty enum in the v2 specification

Basic Information

Please provide a descriptive title for your feedback:

fields[subscriptionOfferCodeOneTimeUseCodeValues] parameter of v1/subscriptionOfferCodeOneTimeUseCodes/{id} is incorrectly defined as an empty enum in the v2 specification

Which area are you seeing an issue with?

App Store Connect API

What type of feedback are you reporting?

Incorrect/Unexpected Behavior

Description

Please describe the issue:

Thanks for releasing all the new endpoints in v2 of the API! Weโ€™re trying to use the CreateAPI tool to generate Swift code from the schema document however have ran into an issue with the v1/subscriptionOfferCodeOneTimeUseCodes/{id} endpoint.

The fields[subscriptionOfferCodeOneTimeUseCodeValues] parameter is defined as an enum with no values. But itโ€™s documented as a plain string in the API documentation (https://developer.apple.com/documentation/appstoreconnectapi/read_one-time_use_offer_code_information).

Since an enum with no values is not valid as part of the OpenAPI specification, I am going to assume that this is a mistake and the enum keyword should be removed:

 {
   "name" : "fields[subscriptionOfferCodeOneTimeUseCodeValues]",
   "in" : "query",
   "description" : "the fields to include for returned resources of type subscriptionOfferCodeOneTimeUseCodeValues",
   "schema" : {
     "type" : "array",
     "items" : {
       "type" : "string",
-      "enum" : [ ]
     }
   },
   "style" : "form",
   "explode" : false,
   "required" : false
 }

But I guess it could also be that there are supposed to be some specific values? Either way I think there is something that needs changing ๐Ÿ™‡๐Ÿปโ€โ™‚๏ธ

You can find some more details here: https://github.com/CreateAPI/CreateAPI/issues/55

Please list the steps you took to reproduce the issue:
  1. Downloaded the v2 API schema
  2. Ran it through a validator
  3. Observed that an empty enum array is not valid in the spec
What did you expect to happen?

A valid Open API Specification (either removing the enum keyword or defining at least one value in the array)

What actually happened?

The schema was not valid because at least 1 item was expected in the enum array

AvdLee commented 1 year ago

I decided to add an empty case manually in the specs, which keeps everything working! Let's hope Apple solves it in the spec later ๐Ÿ™