contrib icon indicating copy to clipboard operation
contrib copied to clipboard

fix(entoas): example annotation

Open prgres opened this issue 1 year ago • 2 comments

Summary

I found an issue with ent and entoas. While checking out a generated openapi.json file I thought it would be nice to have some example values prepared for testing the API.

Description

By browsing the entoas's source code, I found annotations for that [entoas.Example] ready to use:https://github.com/ent/contrib/blob/d262910a1bbd19484e3d449ec7e41f78c8f5f401/entoas/annotation.go#L75

After playing with it for some time, even if it provided examples, it seems that is completely ignored.

Current behaviour

I was adding them like this:

field.String("name").
	Annotations(entoas.Example("zxc")),

In very different scenarios - on fields, edges, and top-level annotations nothing changed. The spec still looks like this

{
  "summary": "Create a new User",
  "description": "Creates a new User and persists it to storage.",
  "operationId": "createUser",
  "requestBody": {
    "description": "User to create",
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
            "properties": {
              "name": {
                "type": "string"
              }
           } 
         }
       }
     }
   }
 }

Root cause

After, some debugging, I found out that there is no code responsible for that. So here I am. The main problem is in the OgenSchema function. It gets a schema for each field type (f.Type.String()) and returns it without any changes - e.g. "string" -> ogen.String(). Anything else is basically ignored.

Fix & changes

After changing if-logic to switch-logic in the generator.go file it only required adding a quick fix:

if ant.Example != nil {
	jv, err := json.Marshal(ant.Example)
	if err != nil {
		return nil, fmt.Errorf("cannot marshal example annotation for field %s", f.Name)
	}
	schema.Example = jv
}

But it came out there was another problem underlying with the types maps. In the upstream, it holds pointers to ogen's schemas so any change which is done on the schema is being propagated to the other fields. My solution for this is a function with a switch statement

(func types(t string) *ogen.Schema {
	switch t {
	case "bool":
		return ogen.Bool()
	case "time.Time":
		return ogen.DateTime()
	case "string":
		return ogen.String()
	case "[]byte":
		return ogen.Bytes()
	case "uuid.UUID":
		return ogen.UUID()
        // ....

For the sake of being future-proof, I also added a unit test that covers that case (func TestOgenSchema_Example(t *testing.T)

prgres avatar Jun 17 '24 13:06 prgres

@a8m @masseelch any updates on this? just a simple feature

prgres avatar Jun 28 '24 07:06 prgres

I am trying to add examples with entoas.Example() annotation and found it doesn't work at all. I stumbled across this pull request and #577 that sadly have no updates from the maintainers. Thank you for your contribution. Hope this can be merged soon.

STommydx avatar Aug 22 '24 16:08 STommydx