zio-http icon indicating copy to clipboard operation
zio-http copied to clipboard

OpenAPI spec to endpoint generator does not recognize field validation

Open stanislav-chetvertkov opened this issue 1 year ago • 8 comments

Is your feature request related to a problem? Please describe.

The code that gets generated based on an openapi spec does not take into account additional field validations, for example, for the following definition

 "schemas": {
      "Pet": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string",
            "minLength": 3
          },
          "tag": {
            "type": "string"
          }
        }
      }
}

and the endpoint using it

  "paths": {
      "post": {
        "summary": "Create a pet",
        "operationId": "createPets",
        "tags": [
          "pets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pet"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Null response"
          },
          "default": {
            "description": "unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },

the case class that gets generated looks like this

case class Pet(
 id: Long,
 name: String,
 tag: Option[String]
)

running a server with a dummy implementation

val httpApp = Pets.createPets.implement(Handler.fromFunctionZIO(pet => {ZIO.logInfo("Pet: " + pet.toString)})).toHttpApp
Server.serve(httpApp)

and issuing a POST request against /pets with payload that should fail validation (the name size should be at least 3 character long)

{
    "id":1,
    "name": "n"
}

gets processed successfully instead

Describe the solution you'd like

changing the generated case class to include zio-schema validations seems to work with no changes to other parts of the generated code

case class Pet(
 id: Long,
 @validate(Validation.minLength(3))
 name: String,
 tag: Option[String]
)

in the corresponding endpoint definition

val createPets=Endpoint(Method.POST / "pets")
  .in[Pet]
  .out[Unit](status = Status.Created)
}

.in[Pet] already responsible for validating input against the schema, and after adding the validation annotation I'm now getting 400 response from the server, However the response body is empty which could be a problem.

Describe alternatives you've considered An alternative could be to generate endpoints that return Either[ValidationError, T] for users to implement and adjust format of validation errors if needed

Additional context the full example https://github.com/stanislav-chetvertkov/zio-http-gen-example

stanislav-chetvertkov avatar Apr 21 '24 05:04 stanislav-chetvertkov

Your described solution should be the right way. However, I am not sure that all Open API validations can be mapped to current schema validations. It might need some extension of zio schema. This would need to be checked

987Nabil avatar May 05 '24 11:05 987Nabil

/bounty $250

jdegoes avatar Jun 05 '24 02:06 jdegoes

💎 $250 bounty • ZIO

Steps to solve:

  1. Start working: Comment /attempt #2786 with your implementation plan
  2. Submit work: Create a pull request including /claim #2786 in the PR body to claim the bounty
  3. Receive payment: 100% of the bounty is received 2-5 days post-reward. Make sure you are eligible for payouts

Thank you for contributing to zio/zio-http!

Add a bountyShare on socials

Attempt Started (GMT+0) Solution
🔴 @stanislav-chetvertkov Jun 8, 2024, 11:39:56 AM WIP
🟢 @987Nabil #2968

algora-pbc[bot] avatar Jun 05 '24 02:06 algora-pbc[bot]

/attempt #2786

Options

stanislav-chetvertkov avatar Jun 08 '24 11:06 stanislav-chetvertkov

I got a bit stuck with adding more validation parameters when parsing openapi schemas

@nowarn("msg=possible missing interpolator")
private[openapi] case class SerializableJsonSchema(
  @fieldName("$ref") ref: Option[String] = None,
  @fieldName("type") schemaType: Option[TypeOrTypes] = None,
  format: Option[String] = None,
  oneOf: Option[Chunk[SerializableJsonSchema]] = None,
  allOf: Option[Chunk[SerializableJsonSchema]] = None,
  anyOf: Option[Chunk[SerializableJsonSchema]] = None,
  @fieldName("enum") enumValues: Option[Chunk[Json]] = None,
  properties: Option[Map[String, SerializableJsonSchema]] = None,
  additionalProperties: Option[BoolOrSchema] = None,
  required: Option[Chunk[String]] = None,
  items: Option[SerializableJsonSchema] = None,
  nullable: Option[Boolean] = None,
  description: Option[String] = None,
  example: Option[Json] = None,
  examples: Option[Chunk[Json]] = None,
  discriminator: Option[OpenAPI.Discriminator] = None,
  deprecated: Option[Boolean] = None,
  contentEncoding: Option[String] = None,
  contentMediaType: Option[String] = None,
  default: Option[Json] = None,
  pattern: Option[String] = None,
  minimum: Option[Double] = None,
  maximum: Option[Double] = None,
)

First, I added minimum: Option[Double] = None, and everything worked and propagated without issues. However, when I added the second field maximum: Option[Double] = None, I started getting the following error:

  .components.schemas.Pet(none of the subtypes could decode the data)

It looks like the error is coming from zio-schema and has something to do with the 22 field restriction, with the last added field being the 23rd.

I'll try to look for a workaround, maybe there is an hlist based approach or schema declarations could be rearranged.

stanislav-chetvertkov avatar Jun 09 '24 06:06 stanislav-chetvertkov

might be a bug - I was able to reproduce it in a simplified form https://github.com/zio/zio-schema/issues/691

stanislav-chetvertkov avatar Jun 10 '24 05:06 stanislav-chetvertkov

/livestream

Watch 987Nabil on Algora TV Click here to watch 987Nabil

987Nabil avatar Jun 26 '24 19:06 987Nabil

I am done with the impl. But another fix for zio-schema is needed https://github.com/zio/zio-schema/pull/698

987Nabil avatar Jun 27 '24 22:06 987Nabil

💡 @987Nabil submitted a pull request that claims the bounty. You can visit your bounty board to reward.

algora-pbc[bot] avatar Jul 15 '24 07:07 algora-pbc[bot]

🎉🎈 @987Nabil has been awarded $250 bounty by ZIO! 🎈🎊

algora-pbc[bot] avatar Aug 15 '24 06:08 algora-pbc[bot]

🎉🎈 @987Nabil has been awarded $200 livestream bonus by Algora! 🎈🎊

algora-pbc[bot] avatar Aug 18 '24 16:08 algora-pbc[bot]