Skip to content
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

Nullable enum ? #165

Open
ctiaffay-conserto opened this issue Dec 2, 2019 · 8 comments
Open

Nullable enum ? #165

ctiaffay-conserto opened this issue Dec 2, 2019 · 8 comments

Comments

@ctiaffay-conserto
Copy link

ctiaffay-conserto commented Dec 2, 2019

Hi there

I have to filter a list of entities on a field which is based on a nullable enum : http://localhost/list?limit=10&filter=val_1

I need to be able to get :

  • all entities (without using the filter at all) : http://localhost/list?limit=10
  • only entities with an enum value (not null in database) : http://localhost/list?limit=10&filter=enum_val1
  • only entities with NO enum value (null in database) : http://localhost/list?limit=10&filter=

The part where I declare and use my enum field :

{
    paths: {
        '/list': {
            get: {
                tags: ['list'],
                summary: 'Return a list of entities',
                operationId: 'list',
                parameters: [
                    {
                        name: 'filter',
                        in: 'query',
                        schema: {
                            $ref: '#/components/schemas/filter',
                        },
                        allowEmptyValue: true,
                        required: false,
                    },
            }
        },
    },
    components: {
        schemas: {
            filter: {
                description: 'nullable enum',
                type: 'string',
                nullable: true,
                enum: ['val_1', 'val_2', 'val_3'],
            },
        }
    }
}

The third is the one (only entities with NO enum value) I can't figure out. The validation middleware keep telling me :

response.data[0].filter should be equal to one of the allowed values: , val_1, val_2, val_3

Thanks for the help

@ctiaffay-conserto
Copy link
Author

Found a workaround to get it working :

enum: [null, '', 'val_1', 'val_2', 'val_3'],

The empty string '' value is needed for the request validator to accept an empty url query param when having filter=
The null vaue is needed for the response validator to accept any null value in response.

But it kind of break the swagger-ui and documentation by adding two possibles values just for the "nullable" validation thing to be working.

@cdimascio
Copy link
Owner

Cool. I appreciate the write-up and the example. It's super helpful. Based on your feedback, it seems their issue is an issue in the request validator's query param handler. I'm sure, with a small fix, we can get this working with null in the enum list. However, since you specified nullable: true that shouldn't be necessary. We'll look into that as well.

In any case, I'm glad you found a workaround in the near term.

@cdimascio
Copy link
Owner

cdimascio commented Dec 30, 2019

@ctiaffay-conserto i believe this will be (at least partially) resolved by #190. once merged, you should be able to set allowEmptyValue: true which should solve the request part

keeping open as the response side must be addressed

@Jackman3005
Copy link

Hello all, I am trying to get the following to work correctly, but unfortunately I receive an error during response validation when the value is null.

This

type:
  type: string
  nullable: true
  enum:
    - ADHOC
    - SCHEDULE
    - ANONYMOUS
    - KIOSK

Causes This

Internal Server Error: /response/type must be equal to one of the allowed values: ADHOC, SCHEDULE, ANONYMOUS, KIOSK
    at ResponseValidator._validate (/my-repo/node_modules/express-openapi-validator/src/middlewares/openapi.response.validator.ts:201:13)
    at /my-repo/node_modules/express-openapi-validator/src/middlewares/openapi.response.validator.ts:73:23
    at ServerResponse.json_hook (/my-repo/node_modules/express-openapi-validator/src/framework/modded.express.mung.ts:39:16)
    at ServerResponse.json_hook (/my-repo/node_modules/express-mung/index.js:56:29)
Errors: [
  {
    path: '/response/type',
    message: 'must be equal to one of the allowed values: ADHOC, SCHEDULE, ANONYMOUS, KIOSK',
    errorCode: 'enum.openapi.validation'
  }
]

"Workaround"

The only thing I have tried that did not cause an error is the following, but it unfortunately also considers an empty object as valid as well...

Notes

  • I could not make it work with type: string as the nullable: true option
  • My attempts at changing to anyOf or allOf did not help the situation.
type:
  oneOf:
    - type: object
      nullable: true
      additionalProperties: false
    - type: string
      enum:
        - ADHOC
        - SCHEDULE
        - ANONYMOUS
        - KIOSK

@cdimascio do you have any suggestions for a schema that would work with the code base today and only allow the enum strings or null?

If not, what needs to be addressed in this library to resolve this?

Thanks in advance for your help and in general your contributions to this library!

Cheers,
Jack

@Tlepel
Copy link

Tlepel commented Nov 13, 2023

We're still running into this as well. However, reading through the OpenAPI specification, it seems as though this is actually expected behaviour. The null value should be included in the enum array, even if the type has a nullable: true property: https://github.com/OAI/OpenAPI-Specification/blob/main/proposals/2019-10-31-Clarify-Nullable.md#if-a-schema-specifies-nullable-true-and-enum-1-2-3-does-that-schema-allow-null-values-see-1900.

Therefore, the validator performs according to the OpenAPI specification and I don't think this actually a bug with the validator.

Perhaps something can be done about the generated schema for enums, but that should be addressed in nestjs/swagger instead

@Jackman3005
Copy link

@Tlepel So are you saying I need to add null in the enum list for my string type?

If so, that doesn't feel quite right. The list of enum values in the example I gave are all string values (I think), so I'm not sure how I can add null to the list of enums without it being interpreted as "null". null and "null" are not equal and although the API accepts null as a valid value it does not accept "null" as a valid value.

@Tlepel
Copy link

Tlepel commented Nov 23, 2023

@Jackman3005 yes, that's right. I agree that it doesn't feel right, but according to the clarification that's how it should be specified.

However, I did some digging and found some more information for OAS 3.1, take a look at this issue: OAI/OpenAPI-Specification#3148

Here a different solution is proposed, which could be what you're looking for:

type:
  type: ['string', 'null']
  enum:
    - ADHOC
    - SCHEDULE
    - ANONYMOUS
    - KIOSK

@Jackman3005
Copy link

@Tlepel I tried something similar to what you suggested as my enum was actually a $ref:

type:
  oneOf:
    - type: "null"
    - $ref: "schemas.yaml#/QuestType"

This required me to drop swagger-cli which was just archived this month in favor of redocly which I was able to get working and it also seemed to work okay with swagger-typescript-api which is another downstream consumer of this OpenAPI definition.

However, after getting that far I found out that express-openapi-validator does not yet support OAS 3.1, per this issue. The error I'm getting on startup of my API is as follows:

openapi.validator: Validating schema
openapi.validator: validation errors [
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail/properties/type/oneOf/0/type",
    "schemaPath": "#/properties/type/enum",
    "keyword": "enum",
    "params": {
      "allowedValues": [
        "array",
        "boolean",
        "integer",
        "number",
        "object",
        "string"
      ]
    },
    "message": "must be equal to one of the allowed values"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail/properties/type/oneOf/0",
    "schemaPath": "#/definitions/Reference/required",
    "keyword": "required",
    "params": {
      "missingProperty": "$ref"
    },
    "message": "must have required property '$ref'"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail/properties/type/oneOf/0",
    "schemaPath": "#/properties/oneOf/items/oneOf",
    "keyword": "oneOf",
    "params": {
      "passingSchemas": null
    },
    "message": "must match exactly one schema in oneOf"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail/properties/type",
    "schemaPath": "#/definitions/Reference/required",
    "keyword": "required",
    "params": {
      "missingProperty": "$ref"
    },
    "message": "must have required property '$ref'"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail/properties/type",
    "schemaPath": "#/properties/properties/additionalProperties/oneOf",
    "keyword": "oneOf",
    "params": {
      "passingSchemas": null
    },
    "message": "must match exactly one schema in oneOf"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail",
    "schemaPath": "#/definitions/Reference/required",
    "keyword": "required",
    "params": {
      "missingProperty": "$ref"
    },
    "message": "must have required property '$ref'"
  },
  {
    "instancePath": "/components/schemas/QuestPrototypeDetail",
    "schemaPath": "#/properties/schemas/patternProperties/%5E%5Ba-zA-Z0-9%5C.%5C-_%5D%2B%24/oneOf",
    "keyword": "oneOf",
    "params": {
      "passingSchemas": null
    },
    "message": "must match exactly one schema in oneOf"
  }
]

Despite the rather verbose output, I'm guessing the first error is the real error, in that null is not a supported type as of yet.

Unfortunately, this still seems to be hung up on AJV support for 3.1 which from what I can tell is only blocked by this one issue which has a $500 bounty on it if anyone is interested to tackle that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants