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

cache loaded remote schemas #117

Closed

Conversation

bonnyr
Copy link

@bonnyr bonnyr commented Sep 24, 2019

when resolving components for loaded schemas and when external resolution is enabled,
kin-openapi will read the remote schema, parse it and resolve it in order to satisfy the reference attribute in the calling schema, but it does so every time a reference needs resolving leading
to unnecessary network traffic request for the same remote schema.

For example:

components:
  schemas:
    AnotherTestSchema:
      type: object
      properties:
        ref1:
          "$ref": http://localhost:7965/components.openapi.yml#/components/schemas/CustomTestSchema
        ref2:
          "$ref": http://localhost:7965/components.openapi.yml#/components/schemas/Name

In the above case, external resolution for components.openapi.yml is performed when parsing the
fragment above only to be done again for ref2. This is recursive and if components.openapi.yml
includes other references they are resolved the same way.

This very quickly leads to major network traffic which at the very least is unnecessary.

This pull request caches the loaded schemas in the swagger loader and returns resolved schemas from the cache once they are loaded.

Added tests to ensure the schemas are loaded only once.

…e they are loaded and resolved.

this avoids hundreds of roundtrips to remote server for schemas that contain multiple references
@bonnyr bonnyr force-pushed the feature/cache-loaded-remote-schemas branch from bd0b49a to 7b543ac Compare September 24, 2019 20:19
}

func NewSwaggerLoader() *SwaggerLoader {
return &SwaggerLoader{}
return &SwaggerLoader{loadedRemoteSchemas: map[url.URL]*Swagger{}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that since this is only initialized/cleared once at creation there is the possibility that you could introduce unwanted behavior for existing users. For example, if you re-use the loader instance to reload an OpenAPI doc and expect to pull in the updated references as well this will fail after the proposed change.

I just checked and this is not a problem for API Sprout since it always creates a new loader. Just calling out that it might be problematic for others.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you mention this in the docs (for example as the documentation for this very function?). It's better than buried in a PR comments :)

Also, could you not initialize the map here but instead check for nil in resolveComponent below? This would save allocation in the case the user does not rely on remote schemas.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah well @danielgtaylor you're not the author... Thanks for pointing this out!

@fenollp
Copy link
Collaborator

fenollp commented Oct 2, 2019

I understand this can be a major PITA and am very curious how this is supposed to be handled by OpenAPI / JSON Schema specs?
Surely caching of HTTP content should at least honor the HTTP cache headers?
Are remote schemas expected to be assumed to never change?

Introducing remote refs immutability may break things, introduce races... so I'm leaning towards "these just have to be immutable". I just can't find the part of the documentation mentioning this?

@fenollp
Copy link
Collaborator

fenollp commented Feb 18, 2021

@bonnyr Hi! I think this should get in. Do you mind rebasing? Thanks

Actually there now is a swaggerLoader.LoadSwaggerFromURIFunc so just adding an implementation of LoadSwaggerFromURIFunc that relies on an outside cache var (maybe behind a mutex) sounds like an appropriate solution and would make for a great example that others can derive from for their own cache semantics needs.

@fenollp
Copy link
Collaborator

fenollp commented Sep 14, 2022

See https://pkg.go.dev/github.com/getkin/kin-openapi/openapi3#ReadFromURIFunc and specifically https://pkg.go.dev/github.com/getkin/kin-openapi/openapi3#URIMapCache which is used by default:

var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))

@fenollp fenollp closed this Sep 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants