Skip to content

$refs used in query parameters do not load #320

@moberegger

Description

@moberegger

Given an Openapi definition like

paths:
  /foo:
    get:
      parameters:
        - name: ids
           in: query
           style: form
           explode: true
           schema:
             type: array
             items:
               $ref: ../components/schemas/id.yml
             uniqueItems: true

json_schemer will raise an UnknownRef error when attempting to validate ids. This is because no ref_resolver is provided and thus its default proc { |uri| raise UnknownRef, uri.to_s } is used. This is happening because build_parameter_schema creates a JSONSchemer.schema inline instead of using the new RefResolver module recently introduced by openapi_first. I believe the same thing is also happening for response headers, because build_responses uses a similar approach for the headers schema. I haven't been able to prove this, though.

Not sure how easy it would be to get those using the same technique used for request bodies and response bodies. Still trying to understand how all of this magic is working 😆.

For now, I was able to workaround this by JSONSchemer.configureing a ref_resolver that would be used as a fallback when openapi_first doesn't provide its own.

        JSONSchemer.configure do |config|
          config.ref_resolver =
            JSONSchemer::CachedResolver.new do |uri|
              OpenapiFirst::FileLoader.load(
                File.join(File.dirname(schema_path), uri.path),
              )
            end
        end

Since that workaround solved my problem, at made me then wonder: instead of creating a new JSONSchemer::CachedResolver for each schema, can we just have a single one that is used by all of them? The current implementation is

      def schema(options = {})
        ref_resolver = JSONSchemer::CachedResolver.new do |uri|
          FileLoader.load(uri.path)
        end
        base_uri = URI::File.build({ path: "#{dir}/" })
        root = JSONSchemer::Schema.new(context, base_uri:, ref_resolver:, **options)
        JSONSchemer::Schema.new(value, nil, root, base_uri:, **options)
      end

The ref_resolver will be initialized for each schema, which means that each schema is getting its own file cache, and so the same sub schema can be loaded multiple times if it has multiple $refs to it from various parent schemas. I imagine the same ref_resolver could be used for all schemas since there is only a single implementation of it, and the uri.path should still be accurate because the schema has a base_uri provided to it. This might help with performance and memory, because it would be able to re-use any cached schemas across the entire Openapi definition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions