swaggest / rest

Web services with OpenAPI and JSON Schema done quick in Go
https://pkg.go.dev/github.com/swaggest/rest
MIT License
362 stars 17 forks source link

Nullable issue #99

Closed chriskolenko closed 1 year ago

chriskolenko commented 1 year ago

After configuring the UUID as follows:

    uuidDef := jsonschema.Schema{}
    uuidDef.AddType(jsonschema.String)
    uuidDef.WithFormat("uuid")
    uuidDef.WithExamples("248df4b7-aa70-47b8-a036-33ac447e668d")
    s.OpenAPICollector.Reflector().AddTypeMapping(uuid.UUID{}, uuidDef)
    s.OpenAPICollector.Reflector().InlineDefinition(uuid.UUID{})

The second occurrence of a UUID in the schemes has a nullable property.

First Occurrence which is working fine:

type Organisation struct {
    es.BaseAggregateSourced

    Avatar string `json:"avatar" required:"true"`
    Name   string `json:"name" required:"true"`
    Url    string `json:"url" required:"true"`
}

      "AggregatesOrganisation": {
        "required": [
          "id",
          "namespace",
          "avatar",
          "name",
          "url"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
          },

Second occurrence which is wrong

type Repository struct {
    es.BaseAggregateSourced

    OrganisationId uuid.UUID `json:"organisation_id" format:"uuid" required:"true"`
    Name           string    `json:"name" required:"true"`
    FullName       string    `json:"full_name" required:"true"`
    DefaultBranch  string    `json:"default_branch" required:"true"`
    CreatedAt      time.Time `json:"created_at" required:"true"`
    Url            string    `json:"url" required:"true"`

    ClusterId uuid.UUID `json:"cluster_id" format:"uuid" required:"true"`
    PlanId    uuid.UUID `json:"plan_id" format:"uuid" required:"true"`
}

      "AggregatesRepository": {
        "required": [
          "id",
          "namespace",
          "organisation_id",
          "name",
          "full_name",
          "default_branch",
          "created_at",
          "url",
          "cluster_id",
          "plan_id"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
          },
vearutop commented 1 year ago

I've tried to reproduce this issue, but could not.

https://go.dev/play/p/qI6d58qaWno

package main

import (
    "context"
    "encoding/json"

    "github.com/google/uuid"
    "github.com/swaggest/jsonschema-go"
    "github.com/swaggest/rest/web"
    "github.com/swaggest/usecase"
)

func main() {
    s := web.DefaultService()

    uuidDef := jsonschema.Schema{}
    uuidDef.AddType(jsonschema.String)
    uuidDef.WithFormat("uuid")
    uuidDef.WithExamples("248df4b7-aa70-47b8-a036-33ac447e668d")

    s.OpenAPICollector.Reflector().AddTypeMapping(uuid.UUID{}, uuidDef)
    s.OpenAPICollector.Reflector().InlineDefinition(uuid.UUID{})

    type BaseAggregateSourced struct {
        ID uuid.UUID `json:"id"`
    }

    type Organisation struct {
        BaseAggregateSourced

        Avatar string `json:"avatar" required:"true"`
    }

    type Repository struct {
        BaseAggregateSourced

        OrganisationId uuid.UUID `json:"organisation_id" format:"uuid" required:"true"`
        Name           string    `json:"name" required:"true"`

        ClusterId uuid.UUID `json:"cluster_id" format:"uuid" required:"true"`
        PlanId    uuid.UUID `json:"plan_id" format:"uuid" required:"true"`
    }

    type Combo struct {
        Org Organisation `json:"org"`
        Rep Repository   `json:"rep"`
    }

    u := usecase.NewInteractor(func(ctx context.Context, input struct{}, output *Combo) error {
        return nil
    })

    s.Get("/foo", u)

    j, _ := json.MarshalIndent(s.OpenAPI, "", " ")

    println(string(j))
}
{
 "openapi": "3.0.3",
 "info": {
  "title": "",
  "version": ""
 },
 "paths": {
  "/foo": {
   "get": {
    "summary": "Main",
    "operationId": "main",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Combo"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Combo": {
    "type": "object",
    "properties": {
     "org": {
      "$ref": "#/components/schemas/Organisation"
     },
     "rep": {
      "$ref": "#/components/schemas/Repository"
     }
    }
   },
   "Organisation": {
    "required": [
     "avatar"
    ],
    "type": "object",
    "properties": {
     "avatar": {
      "type": "string"
     },
     "id": {
      "type": "string",
      "format": "uuid",
      "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
     }
    }
   },
   "Repository": {
    "required": [
     "organisation_id",
     "name",
     "cluster_id",
     "plan_id"
    ],
    "type": "object",
    "properties": {
     "cluster_id": {
      "type": "string",
      "format": "uuid",
      "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
     },
     "id": {
      "type": "string",
      "format": "uuid",
      "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
     },
     "name": {
      "type": "string"
     },
     "organisation_id": {
      "type": "string",
      "format": "uuid",
      "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
     },
     "plan_id": {
      "type": "string",
      "format": "uuid",
      "example": "248df4b7-aa70-47b8-a036-33ac447e668d"
     }
    }
   }
  }
 }
}

Could you try latest version and/or provide a reproducer?

chriskolenko commented 1 year ago

I was able to reproduce it here; https://github.com/chriskolenko/golang-rest

vearutop commented 1 year ago

Thank you for the reproducer.

Please try v0.2.35.