pb33f/libopenapi

Quickstart tutorial leads to `nil pointer dereference error`

baderj opened this issue · 3 comments

You are linking to Parsing OpenAPI files using go guide as the Quick-start tutorial for libopenapi.

Following the tutorial (while fixing the three different spellings of docModel, docmodel and model) leads to a panic: runtime error: invalid memory address or nil pointer dereference when printing the schemas. Steps to reproduce:

  1. curl https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml > petstorev3.json
  2. go get github.com/pb33f/libopenapi
  3. Create this main.go file:
package main

import (
	"fmt"
	"os"

	"github.com/pb33f/libopenapi"
)

func main() {
	petstore, _ := os.ReadFile("petstorev3.json")
	document, err := libopenapi.NewDocument(petstore)
	if err != nil {
		panic(fmt.Sprintf("cannot create new document: %e", err))
	}
	docModel, errors := document.BuildV3Model()
	if len(errors) > 0 {
		for i := range errors {
			fmt.Printf("error: %e\n", errors[i])
		}
		panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
	}

	// The following fails after the first iteration
	for schemaPairs := docModel.Model.Components.Schemas.First(); schemaPairs != nil; schemaPairs = schemaPairs.Next() {
		schemaName := schemaPairs.Key()
		schema := schemaPairs.Value()
		fmt.Printf("Schema '%s' has %d properties\n", schemaName, schema.Schema().Properties.Len())
	}
}
  1. go run main.go

This produces

Schema 'Pet' has 3 properties
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7cbf4e]

goroutine 1 [running]:
main.main()
        /home/bug/main.go:28 +0x1ce
exit status 2

Tested with v0.16.10 of libopenapi and 1.0.0 of the Swagger Petstore specification.

This error is expected, as Pets does not have any properties as it is an array of Pet.

Maybe you could just add a small snippet as the quickstart guide instead of the the external tutorial.

Thank you for this work. I like your idea.

The code should read like this. I will update it and add to the quick start.

package main

import (
    "fmt"
    "github.com/pb33f/libopenapi"
    "os"
)

func main() {
    petstore, _ := os.ReadFile("petstorev3.json")
    document, err := libopenapi.NewDocument(petstore)
    if err != nil {
        panic(fmt.Sprintf("cannot create new document: %e", err))
    }
    docModel, errors := document.BuildV3Model()
    if len(errors) > 0 {
        for i := range errors {
            fmt.Printf("error: %e\n", errors[i])
        }
        panic(fmt.Sprintf("cannot create v3 model from document: %d errors reported", len(errors)))
    }

    // The following fails after the first iteration
    for schemaPairs := docModel.Model.Components.Schemas.First(); schemaPairs != nil; schemaPairs = schemaPairs.Next() {

        // get the name of the schema
        schemaName := schemaPairs.Key()

        // get the schema object from the map
        schemaValue := schemaPairs.Value()

        // build the schema
        schema := schemaValue.Schema()

        // if the schema has properties, print the number of properties
        if schema != nil && schema.Properties != nil {
            fmt.Printf("Schema '%s' has %d properties\n", schemaName, schema.Properties.Len())
        }
    }
}

Readme has been updated with this exact code walk through, thank you for the nudge.

Also the blog post has been updated.