counterfact icon indicating copy to clipboard operation
counterfact copied to clipboard

counterfact does not support $ref with external yaml files

Open sugiruu opened this issue 8 months ago • 6 comments

As the title says, counterfact does not seem to support referencing yaml files in the openapi specification. Example:

paths:
  /metrics:
    get:
      operationId: getMetrics
      tags:
        - Default
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: 'components/metrics.yaml#/components/schemas/MetricsResponse'
              examples:
                default:
                  $ref: 'components/examples.yaml#/examples/MetricsResponseExample'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: 'components/errors.yaml#/components/schemas/ErrorResponse'

When opening the swagger docs, I see the following error:

Image

Response schema

Image

When using a single openapi spec file, it works as expected

Image

sugiruu avatar Mar 28 '25 17:03 sugiruu

Found a couple issues on json-schema-ref-parser that could be related

  • https://github.com/APIDevTools/json-schema-ref-parser/issues/199
  • https://github.com/APIDevTools/json-schema-ref-parser/issues/376

I did some digging and the bundled schema has some weird $ref values:

{
  type: 'array',
    items: {
    '$ref': '#/paths/~1metrics/get/responses/200/content/application~1json/schema/allOf/0/properties/data/items'
  }
}

sugiruu avatar Mar 28 '25 17:03 sugiruu

For anyone having the same problem, my workaround was to bundle my openapi spec using redocly and use that file to serve counterfact. The downside is that the hot-reload will not work automatically.

package.json

{
  "scripts": {
    "openapi:bundle": "bunx redocly bundle api-spec/openapi.yaml -o api-spec/openapi.json",
    "serve:mock": "bun run openapi:bundle && counterfact api-spec/openapi.json lib/server/mock"
  }
}

sugiruu avatar Mar 28 '25 18:03 sugiruu

Thanks! Is there a problem in Counterfact itself or just Swagger? I thought I'd worked around by merging external files at runtime but may have missed something.

pmcelhaney avatar Mar 29 '25 19:03 pmcelhaney

It works if I use $.response[200].json() to return static data. Using $.response[200].random() returns a 500 status with the following error:

The Open API document does not specify a response for status code 200

These are the files it generates:

import type { items } from "../../../../../../../../~1metrics/get/responses/200/content/application~1json/schema/allOf/0/properties/data/items.js";

export type _0 = {
  data: Array<items>;
  meta?: { total?: number; next?: string; prev?: string };
};

Image

sugiruu avatar Mar 31 '25 00:03 sugiruu

Thanks, I'll have a look. If can you share the relevant sections from metrics.yaml and errors.yaml, that will help.

pmcelhaney avatar Mar 31 '25 19:03 pmcelhaney

Sure!

openapi.yaml:

paths:
  /metrics:
    get:
      operationId: getMetrics
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: 'components/metrics.yaml#/components/schemas/MetricsResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: 'components/errors.yaml#/components/schemas/ErrorResponse'

metrics.yaml:

components:
  schemas:
    MetricAttributes:
      type: object
      required: [value]
      properties:
        value:
          type: integer
          example: 20
        title:
          type: string
        description:
          type: string

    MetricResource:
      allOf:
        - type: object
          properties:
            type:
              type: string
              enum: [metric]
              example: metric
            attributes:
              $ref: '#/components/schemas/MetricAttributes'

    MetricsResponse:
      allOf:
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/MetricResource'

errors.yaml

components:
  schemas:
    ErrorResponse:
      type: object
      required: [status, statusCode, message]
      properties:
        title:
          type: string
        code:
          type: string
          example: ERR_PERMISSION
        message:
          type: string
        name:
          type: string
          example: BadRequestError

sugiruu avatar Apr 04 '25 04:04 sugiruu