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

Support loading via http.FileSystem #311

Closed
hottestseason opened this issue Feb 28, 2021 · 7 comments · Fixed by #316
Closed

Support loading via http.FileSystem #311

hottestseason opened this issue Feb 28, 2021 · 7 comments · Fixed by #316

Comments

@hottestseason
Copy link
Contributor

It is great if this library can load with http.FileSystem because we can embed specification files into single binary with Go1.16's embed feature

package main

import (
	"embed"
	"log"
	"net/http"

	"github.com/getkin/kin-openapi/openapi3"
)

//go:embed spec/*
var spec embed.FS

func main() {
	loader := openapi3.NewSwaggerLoader()
	loader.IsExternalRefsAllowed = true

	swagger, err := loader.LoadSwaggerFromFileSystem(http.FS(spec), "spec/openapi.yml")
	if err != nil {
		panic(err)
	}

	log.Printf("%s\n", swagger.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties["foo"].Value.Type)
}
openapi: "3.0.0"
info:
  version: "1.0"
  title: example
paths:
  /foo:
    $ref: ./paths/foo.yml
get:
  parameters:
  responses:
    "200":
      description: OK
      content:
        application/json:
          schema:
            type: object
            properties:
              foo:
                type: string
                example: foo
@fenollp
Copy link
Collaborator

fenollp commented Mar 1, 2021

Is this not doable today with a LoadSwaggerFromURIFunc?

@hottestseason
Copy link
Contributor Author

Unfortunately it doesn't works.

package main

import (
	"context"
	"embed"
	"fmt"
	"net/url"
	"path/filepath"

	"github.com/getkin/kin-openapi/openapi3"
)

//go:embed spec/*
var spec embed.FS

func main() {
	ctx := context.Background()

	loader := openapi3.NewSwaggerLoader()
	loader.IsExternalRefsAllowed = true
	loader.LoadSwaggerFromURIFunc = func(loader *openapi3.SwaggerLoader, url *url.URL) (*openapi3.Swagger, error) {
		data, err := spec.ReadFile(filepath.Join("spec", url.Path))
		if err != nil {
			panic(err)
		}
		swagger, err := loader.LoadSwaggerFromData(data)
		if err != nil {
			panic(err)
		}
		return swagger, nil
	}
	swagger, err := loader.LoadSwaggerFromFile("openapi.yml")
	if err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", swagger.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema)

	if err = swagger.Validate(ctx); err != nil {
		panic(err)
	}
}
% go run main.go
panic: open ./components/Bar.yml: no such file or directory

goroutine 1 [running]:
main.main.func1(0xc0001a09a0, 0xc0000ba240, 0x30, 0x139c680, 0x1)
	/Users/sumihiko.natsu/src/github.com/hottestseason/kin-openapi/main.go:28 +0x137
github.com/getkin/kin-openapi/openapi3.(*SwaggerLoader).loadSwaggerFromFileInternal(0xc0001a09a0, 0x13b5305, 0xb, 0x13a1a40, 0xc000052701, 0xc0001a09a0)
	/Users/sumihiko.natsu/src/github.com/hottestseason/kin-openapi/openapi3/swagger_loader.go:143 +0x131
github.com/getkin/kin-openapi/openapi3.(*SwaggerLoader).LoadSwaggerFromFile(0xc0001a09a0, 0x13b5305, 0xb, 0xc000000180, 0x200000003, 0xc000000180)
	/Users/sumihiko.natsu/src/github.com/hottestseason/kin-openapi/openapi3/swagger_loader.go:136 +0x78
main.main()
	/Users/sumihiko.natsu/src/github.com/hottestseason/kin-openapi/main.go:32 +0x6f
exit status 2

It looks LoadSwaggerFromURIFunc is only used while loading the root OpenAPI spec file, but when resolving references ioutil.ReadFile will be used.

data, err := ioutil.ReadFile(location.Path)

@fenollp
Copy link
Collaborator

fenollp commented Mar 2, 2021

Then

data, err := ioutil.ReadFile(location.Path)
needs to use the func and be passed swaggerLoader :)
Could you update your PR to do this change and provide an example func that uses http.FS?

@fenollp
Copy link
Collaborator

fenollp commented Mar 2, 2021

Doing this actually also solves #231

@hottestseason
Copy link
Contributor Author

OK, I'll try.
Thanks for your advice!!

@hottestseason
Copy link
Contributor Author

I prepared another PR #316

package main

import (
	"context"
	"embed"
	"fmt"
	"github.com/getkin/kin-openapi/openapi3"
	"net/url"
)

//go:embed spec/*
var spec embed.FS

func main() {
	ctx := context.Background()

	loader := openapi3.NewSwaggerLoader()
	loader.IsExternalRefsAllowed = true
	loader.ReadFromURIFunc = func(loader *openapi3.SwaggerLoader, url *url.URL) ([]byte, error) {
		fmt.Println(url.Path)
		return spec.ReadFile(url.Path)
	}
	swagger, err := loader.LoadSwaggerFromFile("spec/openapi.yml")
	if err != nil {
		panic(err)
	}

	if err = swagger.Validate(ctx); err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", swagger.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema.Value)
}
% go run main.go
spec/openapi.yml
spec/components/Bar.yml
spec/components/Foo.yml
spec/openapi.yml
spec/components/Bar.yml
spec/paths/foo.yml
spec/openapi.yml
spec/components/Foo.yml
spec/openapi.yml
&{ExtensionProps:{Extensions:map[]} OneOf:[] AnyOf:[] AllOf:[] Not:<nil> Type:object Title: Format: Description: Enum:[] Default:<nil> Example:<nil> ExternalDocs:<nil> AdditionalPropertiesAllowed:<nil> UniqueItems:false ExclusiveMin:false ExclusiveMax:false Nullable:false ReadOnly:false WriteOnly:false AllowEmptyValue:false XML:<nil> Deprecated:false Min:<nil> Max:<nil> MultipleOf:<nil> MinLength:0 MaxLength:<nil> Pattern: compiledPattern:<nil> MinItems:0 MaxItems:<nil> Items:<nil> Required:[] Properties:map[foo:0xc00000ee40] MinProps:0 MaxProps:<nil> AdditionalProperties:<nil> Discriminator:<nil>}

@fenollp
Copy link
Collaborator

fenollp commented Mar 3, 2021

Very nice, thank you! I like this a lot.
I'll merge your PR and in a next PR I'll get rid of the old Func which does not bring anything from the uses I can see.
Also I'll look into adding your snippet above as an example/test.

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