Search code examples
typescriptswaggerfastify

@fastify/swagger - how to use $ref


Iam having issue with referencing my definitions in fastify route registration.

Iam using "@fastify/swagger": "^8.3.1" and generating definitions via "ts-json-schema-generator": "^1.2.0".

This is my index.ts

    const server = fastify()  
  
    const wholeSchema = {
    swagger: {
        info: {
            title: 'Spajzka API',
            description: 'Spajzka API documentation',
            version: '0.1.0'
        },
        host: '127.0.0.1:3010',
        schemes: ['http'],
        consumes: ['application/json'],
        produces: ['application/json'],
        securityDefinitions: {
            apiKey: {
                type: 'apiKey',
                name: 'apiKey',
                in: 'header'
            }
        },
        definitions: schema.definitions
    }
}

await server.register(fastifySwagger, wholeSchema)

registerRoutes(server);

await server.ready()
server.swagger()

routes.ts and route registration

export const registerRoutes = (server: any) => {
    server.route({
        method: 'GET',
        url: '/item/:id',
        schema: {
            description: 'Get item by id',
            tags: ['item'],
            summary: 'Get item by id',
            params: {
                type: 'object',
                properties: {
                    id: { type: 'number' }
                }
            },
            response: {
                200: {
                    schema: {
                        type: 'object',
                        $ref: '#/definitions/item'
                    }
                }
            }
        },
        handler: (req: any, reply: any) => {
            reply.send()
        }
    })
}

With this setup Iam getting this error.

FastifyError: Failed building the serialization schema for GET: /item/:id, due to error Cannot find reference "#/definitions/item"

When I remove $ref it works. Here is swagger.json.

{"swagger":"2.0","info":{"title":"Spajzka API","description":"Spajzka API documentation","version":"0.1.0"},"definitions":{"Item":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"price":{"type":"number"},"isOnBuylist":{"type":"boolean"},"amount":{"type":"number"}},"required":["id","name","price","isOnBuylist","amount"],"additionalProperties":false}},"paths":{"/item/{id}":{"get":{"summary":"Get item by id","description":"Get item by id","tags":["item"],"parameters":[{"type":"number","required":true,"in":"path","name":"id"}],"responses":{"200":{"description":"Default Response","schema":{"type":"object","properties":{"schema":{"type":"object"}}}}}}},"/item":{"get":{"summary":"Get items","tags":["item"],"responses":{"200":{"description":"Default Response","schema":{"type":"object","properties":{"schema":{"type":"array"}}}}}}}},"host":"127.0.0.1:3010","schemes":["http"],"consumes":["application/json"],"produces":["application/json"],"securityDefinitions":{"apiKey":{"type":"apiKey","name":"apiKey","in":"header"}}}

This is wholeSchema from registration

{
  "swagger": {
    "info": {
      "title": "Spajzka API",
      "description": "Spajzka API documentation",
      "version": "0.1.0"
    },
    "host": "127.0.0.1:3010",
    "schemes": [
      "http"
    ],
    "consumes": [
      "application/json"
    ],
    "produces": [
      "application/json"
    ],
    "securityDefinitions": {
      "apiKey": {
        "type": "apiKey",
        "name": "apiKey",
        "in": "header"
      }
    },
    "definitions": {
      "Item": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number"
          },
          "name": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "isOnBuylist": {
            "type": "boolean"
          },
          "amount": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "name",
          "price",
          "isOnBuylist",
          "amount"
        ],
        "additionalProperties": false
      }
    }
  }
}

When I then add manualy $ref its working properly.

How can I make it to work during registration or just ignore error?


Solution

  • I was unable to solve this issue this way. So I changed my aproach and tried to add schema via fastify.addSchema()

    I had to alter schema generated output from 'ts-json-schema-generator'

    With this code I split definitios and add its name as $id so fastify can correctly link it $ref.

        for (const key in schema.definitions) {
        const newSchema = Object.assign({}, schema.definitions[key] ,{$id: key})
        server.addSchema(newSchema)
        }
    

    And with this code as parameter in swagger register. I was able to change name of them from def-# to my preference.

            refResolver: {
            buildLocalReference(json, baseUri, fragment, i) {
                return `${json.$id}Model`
            }}
    

    Then I was able to use refs like $ref: 'Item'