Skip to content

Add support for nested references #2144

Closed

Description

@VYDocuWare

Describe the bug

var openApiStringReader = new OpenApiStringReader();
var result = openApiStringReader.Read(openApiDoc, out var diagnostic);

When I use the above code with openApiDoc = to the attached yaml, I get the following exception:

Microsoft.OpenApi.Exceptions.OpenApiException: 'The reference string '/components/schemas/CurrentTrack/properties/title' has invalid format.'

The yaml is valid according to the Swagger Editor (https://editor.swagger.io/)

OpenApi File To Reproduce

openapi: 3.0.0
info:
    version: 1.0.0
    title: Radio.co Public API
    contact:
        name: API Support
        url: help.radio.co
        email: help@radio.co
    x-logo:
        url: "https://radio.co/assets/downloads/Logo--Full-Colour-for-Light-Backgrounds.png"
    description: Radio.co public API
servers:
    - url: "https://public.radio.co"
paths:
    "/stations/{station_id}/status":
        get:
            summary: Get station status
            description: Get the current status of a station.
            operationId: statusAction
            tags:
                - Status
            parameters:
                - $ref: "#/components/parameters/station_id"
            responses:
                "200":
                    description: Station status
                    content:
                        application/json:
                            schema:
                                title: Status
                                type: object
                                description: The station status
                                required:
                                    - status
                                    - source
                                    - collaborators
                                    - relays
                                    - current_track
                                    - history
                                    - logo_url
                                    - streaming_hostname
                                    - outputs
                                properties:
                                    status:
                                        type: string
                                        description: The station status.
                                        enum:
                                            - online
                                            - offline
                                        example: online
                                    source:
                                        title: Source
                                        type: object
                                        description: The source of station playback.
                                        required:
                                            - type
                                            - collaborator
                                            - relay
                                        properties:
                                            type:
                                                type: string
                                                description: The source type.
                                                enum:
                                                    - automated
                                                    - live
                                                example: automated
                                            collaborator:
                                                nullable: true
                                                allOf:
                                                    - $ref: "#/components/schemas/Collaborator"
                                            relay:
                                                nullable: true
                                                allOf:
                                                    - $ref: "#/components/schemas/Relay"
                                    collaborators:
                                        type: array
                                        description: Currently connected collaborators.
                                        items:
                                            $ref: "#/components/schemas/Collaborator"
                                    relays:
                                        type: array
                                        description: Currently connected relays.
                                        items:
                                            $ref: "#/components/schemas/Relay"
                                    current_track:
                                        $ref: "#/components/schemas/CurrentTrack"
                                    history:
                                        type: array
                                        description: An array of history items.
                                        items:
                                            type: object
                                            required:
                                                - title
                                            properties:
                                                title:
                                                    $ref: "#/components/schemas/CurrentTrack/properties/title"
                                    logo_url:
                                        type: string
                                        description: The station logo URL.
                                        format: uri
                                        example: "https://images.radio.co/station_logos/s7ee52dd88.20161028115811.png"
                                    streaming_hostname:
                                        type: string
                                        description: A hostname. Should be valid according to RFC1123
                                        pattern: '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
                                        example: stream.radio.co
                                    outputs:
                                        type: array
                                        description: Possible outputs.
                                        items:
                                            title: Output
                                            type: object
                                            required:
                                                - name
                                                - format
                                                - bitrate
                                            properties:
                                                name:
                                                    type: string
                                                    description: Output name.
                                                    pattern: "^[a-z0-9]+$"
                                                format:
                                                    type: string
                                                    description: Output format.
                                                    enum:
                                                        - MP3
                                                        - AAC
                                                bitrate:
                                                    type: number
                                                    description: Output bitrate.
                                                    enum:
                                                        - 16
                                                        - 32
                                                        - 48
                                                        - 64
                                                        - 96
                                                        - 128
                                                        - 192
                                                        - 256
                                                        - 320
    "/stations/{station_id}/history":
        get:
            parameters:
                - $ref: "#/components/parameters/station_id"

            summary: Get station history
            description: Get the track history of a station.
            operationId: getHistoryAction
            tags:
                - History
            responses:
                "200":
                    description: Station track history
                    content:
                        application/json:
                            schema:
                                title: History
                                type: object
                                description: The station track history
                                required:
                                    - tracks
                                properties:
                                    tracks:
                                        type: array
                                        description: Track history items.
                                        maxItems: 20
                                        items:
                                            title: Track
                                            type: object
                                            required:
                                                - title
                                                - start_time
                                                - artwork_url
                                            properties:
                                                title:
                                                    $ref: "#/components/schemas/CurrentTrack/properties/title"
                                                start_time:
                                                    type: string
                                                    description: Date and time of when the track started.
                                                    format: date-time
                                                artwork_url:
                                                    $ref: "#/components/schemas/Artwork/properties/url"
    "/stations/{station_id}/next":
        get:
            summary: Get upcoming track
            description: Get the upcoming track for a station.
            operationId: getNextTrackAction
            tags:
                - Next
            parameters:
                - in: path
                  name: station_id
                  description: Owning station id.
                  required: true
                  schema:
                      $ref: "#/components/parameters/station_id/schema"
            responses:
                "200":
                    description: Upcoming track
                    content:
                        application/json:
                            schema:
                                title: Next
                                type: object
                                description: The station track history
                                required:
                                    - station_name
                                    - next_track
                                properties:
                                    station_name:
                                        title: Station name
                                        type: string
                                        example: MCR Live
                                    next_track:
                                        title: Track
                                        type: object
                                        description: Upcoming track.
                                        required:
                                            - title
                                            - artwork_url
                                            - artwork_url_large
                                        properties:
                                            title:
                                                $ref: "#/components/schemas/CurrentTrack/properties/title"
                                            artwork_url:
                                                $ref: "#/components/schemas/Artwork/properties/url"
                                            artwork_url_large:
                                                $ref: "#/components/schemas/Artwork/properties/large_url"
    "/stations/{station_id}/requests":
        parameters:
            - $ref: "#/components/parameters/station_id"
        post:
            summary: Request a track
            description: Request a track
            operationId: requestTrackAction
            tags:
                - Requests
            requestBody:
                description: Requested track
                required: true
                content:
                    application/json:
                        schema:
                            title: Requested Track
                            type: object
                            required:
                                - track_id
                            properties:
                                track_id:
                                    type: integer
                                    example: 1337
                                    minimum: 0
                    application/xml:
                        schema:
                            type: object
                            properties:
                                "":
                                    type: string
                        examples:
                            example-1:
                                value:
                                    "": string
            responses:
                "201":
                    description: Track requested.
                "403":
                    description: Requests disabled.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/StandardErrorSchema"
                "404":
                    description: Requested track not found.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/StandardErrorSchema"
                "409":
                    description: You have already requested this track.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/StandardErrorSchema"
                "429":
                    description: You can not make any more requests at this time.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/StandardErrorSchema"
    "/stations/{station_id}/requests/tracks":
        get:
            summary: Get request-able tracks
            description: Get the available tracks for request for a station
            operationId: getRequestableTracks
            parameters:
                - $ref: "#/components/parameters/station_id"
            tags:
                - Requests
            responses:
                "200":
                    description: Available tracks
                    content:
                        application/json:
                            schema:
                                title: Request-able Tracks
                                type: object
                                required:
                                    - tracks
                                properties:
                                    tracks:
                                        description: Request-able track items.
                                        type: array
                                        items:
                                            title: Track
                                            type: object
                                            properties:
                                                id:
                                                    type: number
                                                    example: 1337
                                                    title: Track identity
                                                    description: The identity of the track.
                                                    minimum: 1
                                                artist:
                                                    type: string
                                                    description: Track artist
                                                    example: Darude
                                                title:
                                                    $ref: "#/components/schemas/CurrentTrack/properties/title"
                                                artwork:
                                                    $ref: "#/components/schemas/Artwork"
    "/stations/{station_id}/embed/schedule":
        get:
            parameters:
                - $ref: "#/components/parameters/station_id"
            summary: getSchedule
            tags: [Schedule]
            operationId: getStationSchedule
            description: Get a 2 week period of a stations schedule
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    data:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/PublicSchedule"
components:
    parameters:
        station_id:
            in: path
            name: station_id
            description: Owning station id.
            required: true
            schema: {}
    schemas:
        Artwork:
            title: Artwork
            type: object
            properties:
                url:
                    type: string
                    format: uri
                    nullable: true
                large_url:
                    type: string
                    format: uri
                    nullable: true
        Collaborator:
            title: Collaborator
            type: object
            description: The currently broadcasting collaborator.
            required:
                - id
                - name
                - status
            properties:
                id:
                    type: string
                    example: ud160d49ee
                    pattern: "^u[a-f0-9]{9}$"
                    description: User identity.
                name:
                    type: string
                    description: User name.
                    example: John Doe
                status:
                    type: string
                    description: Collaborator status.
                    enum:
                        - streaming
                        - pending
                    example: pending
        CurrentTrack:
            title: Current Track
            type: object
            description: Currently playing track.
            required:
                - title
                - start_time
                - artwork_url
                - artwork_url_large
            properties:
                title:
                    type: string
                    description: Track title
                    example: 2018 Summer Jingle
                start_time:
                    type: string
                    description: Date and time of when the track started.
                    format: date-time
                artwork_url:
                    $ref: "#/components/schemas/Artwork/properties/url"
                artwork_url_large:
                    $ref: "#/components/schemas/Artwork/properties/large_url"
        Relay:
            title: Relay
            type: object
            description: The currently live relay.
            required:
                - id
                - url
                - status
            properties:
                id:
                    type: integer
                    example: 1337
                    minimum: 1
                    description: Relay identity.
                url:
                    type: string
                    description: Relay URL.
                    format: uri
                    example: "http://streaming.radio.co/s307b15171/listen"
                status:
                    type: string
                    description: Relay status
                    enum:
                        - connected
                    example: connected
        StandardErrorSchema:
            title: StandardErrorSchema
            type: object
            description: Standard error response
            required:
                - errors
            properties:
                errors:
                    type: array
                    description: collection of errors
                    items:
                        title: Error
                        type: object
                        description: Standard error
                        required:
                            - code
                            - message
                        properties:
                            code:
                                type: integer
                                minimum: 1
                                description: Error code. Will mirror a HTTP error code if we dont have anything more specific
                            message:
                                type: string
                                description: User friendly error message
                                example: Track not found
        PublicSchedule:
            title: PublicSchedule
            type: object
            description: Contains event and playlist data
            properties:
                start:
                    type: string
                    format: date-time
                end:
                    type: string
                    format: date-time
                playlist:
                    type: object
                    required:
                        - name
                        - colour
                        - artist
                        - title
                        - artwork
                    properties:
                        name:
                            type: string
                        colour:
                            type: string
                            example: "#123abc"
                            pattern: "^#[0-9a-fA-F]{6}$"
                        artist:
                            type: string
                        title:
                            type: string
                        artwork:
                            type: string
                            nullable: true
                            format: uri
            required:
                - start
                - end
                - playlist
tags:
    - name: History
      description: History
    - name: Next
      description: Next
    - name: Requests
      description: Requests
    - name: Status
      description: Requests
x-hasEquivalentPaths: true

Expected behavior
The yaml is parsed without issue.

Activity

  1. darrelmiller commented on Feb 12, 2025

    @darrelmiller
    Member

    The library currently only supports referencing "components". i.e. it does not support referencing sub schemas. Our plan is to bring that support to the v2 of the library while we are adding support for $id references into sub schemas.

    There is some ambiguity in the specification https://spec.openapis.org/oas/v3.1.1.html#reference-object that says...

    A simple object to allow referencing other components in the OpenAPI Description,

    How you interpret "components" changes how you implement the specification.

  2. VYDocuWare commented on Feb 13, 2025

    @VYDocuWare
    Author

    Thanks for the response. Can you give a (possibly rough) estimate of when support will be added?

  3. changed the title [-]OpenApiStringReader failing to read a valid OpenApi file[/-] [+]Add support for nested references[/+] on Mar 10, 2025
  4. darrelmiller commented on Mar 12, 2025

    @darrelmiller
    Member

    From a discussion with the team:

    • Nested references only work for references to schemas
    • Find schema component based on first segment after "#/components"
    • Use JSON Pointer location rules to identify the target schema using the remaining part of the $ref URL.
    • Do not traverse into $refs in the target path.

    We expect this functionality to "fast follow" our v2 GA release.

    If you would like to submit a PR then we could get this out sooner.

  5. VYDocuWare commented on Mar 14, 2025

    @VYDocuWare
    Author

    Thanks for the information. Where can I find information on when the v2 GA release will happen?

  6. baywet commented on Aug 25, 2025

    @baywet
    Member

    This is now supported with the V2 of the library which was released about 2 months ago now :)
    Closing.
    Let us know if you have any additional comments or questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    external-referencepriority:p1High priority but not blocking. Causes major but not critical loss of functionality SLA <=7daysstatus:waiting-for-internal-feedbackNeeds internal stakeholder(s) input to resolve

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions