diff --git a/.changeset/pink-sloths-nail.md b/.changeset/pink-sloths-nail.md
new file mode 100644
index 0000000000..a59bfb0990
--- /dev/null
+++ b/.changeset/pink-sloths-nail.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-api-docs': patch
+---
+
+Export `apiDocsConfigRef` from `api-docs` plugin to allow extending it with
+custom API rendering.
diff --git a/plugins/api-docs/dev/asyncapi-example-api.yaml b/plugins/api-docs/dev/asyncapi-example-api.yaml
new file mode 100644
index 0000000000..725811d0cc
--- /dev/null
+++ b/plugins/api-docs/dev/asyncapi-example-api.yaml
@@ -0,0 +1,221 @@
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: streetlights
+ description: The Smartylighting Streetlights API allows you to remotely manage the city lights.
+ tags:
+ - mqtt
+spec:
+ type: asyncapi
+ lifecycle: production
+ owner: team-c
+ definition: |
+ asyncapi: 2.0.0
+ info:
+ title: Streetlights API
+ version: '1.0.0'
+ description: |
+ The Smartylighting Streetlights API allows you to remotely manage the city lights.
+
+ ### Check out its awesome features:
+
+ * Turn a specific streetlight on/off 🌃
+ * Dim a specific streetlight 😎
+ * Receive real-time information about environmental lighting conditions 📈
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0
+
+ servers:
+ production:
+ url: api.streetlights.smartylighting.com:{port}
+ protocol: mqtt
+ description: Test broker
+ variables:
+ port:
+ description: Secure connection (TLS) is available through port 8883.
+ default: '1883'
+ enum:
+ - '1883'
+ - '8883'
+ security:
+ - apiKey: []
+ - supportedOauthFlows:
+ - streetlights:on
+ - streetlights:off
+ - streetlights:dim
+ - openIdConnectWellKnown: []
+
+ defaultContentType: application/json
+
+ channels:
+ smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured:
+ description: The topic on which measured values may be produced and consumed.
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ subscribe:
+ summary: Receive information about environmental lighting conditions of a particular streetlight.
+ operationId: receiveLightMeasurement
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ message:
+ $ref: '#/components/messages/lightMeasured'
+
+ smartylighting/streetlights/1/0/action/{streetlightId}/turn/on:
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ publish:
+ operationId: turnOn
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ message:
+ $ref: '#/components/messages/turnOnOff'
+
+ smartylighting/streetlights/1/0/action/{streetlightId}/turn/off:
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ publish:
+ operationId: turnOff
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ message:
+ $ref: '#/components/messages/turnOnOff'
+
+ smartylighting/streetlights/1/0/action/{streetlightId}/dim:
+ parameters:
+ streetlightId:
+ $ref: '#/components/parameters/streetlightId'
+ publish:
+ operationId: dimLight
+ traits:
+ - $ref: '#/components/operationTraits/kafka'
+ message:
+ $ref: '#/components/messages/dimLight'
+
+ components:
+ messages:
+ lightMeasured:
+ name: lightMeasured
+ title: Light measured
+ summary: Inform about environmental lighting conditions for a particular streetlight.
+ contentType: application/json
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: "#/components/schemas/lightMeasuredPayload"
+ turnOnOff:
+ name: turnOnOff
+ title: Turn on/off
+ summary: Command a particular streetlight to turn the lights on or off.
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: "#/components/schemas/turnOnOffPayload"
+ dimLight:
+ name: dimLight
+ title: Dim light
+ summary: Command a particular streetlight to dim the lights.
+ traits:
+ - $ref: '#/components/messageTraits/commonHeaders'
+ payload:
+ $ref: "#/components/schemas/dimLightPayload"
+
+ schemas:
+ lightMeasuredPayload:
+ type: object
+ properties:
+ lumens:
+ type: integer
+ minimum: 0
+ description: Light intensity measured in lumens.
+ sentAt:
+ $ref: "#/components/schemas/sentAt"
+ turnOnOffPayload:
+ type: object
+ properties:
+ command:
+ type: string
+ enum:
+ - on
+ - off
+ description: Whether to turn on or off the light.
+ sentAt:
+ $ref: "#/components/schemas/sentAt"
+ dimLightPayload:
+ type: object
+ properties:
+ percentage:
+ type: integer
+ description: Percentage to which the light should be dimmed to.
+ minimum: 0
+ maximum: 100
+ sentAt:
+ $ref: "#/components/schemas/sentAt"
+ sentAt:
+ type: string
+ format: date-time
+ description: Date and time when the message was sent.
+
+ securitySchemes:
+ apiKey:
+ type: apiKey
+ in: user
+ description: Provide your API key as the user and leave the password empty.
+ supportedOauthFlows:
+ type: oauth2
+ description: Flows to support OAuth 2.0
+ flows:
+ implicit:
+ authorizationUrl: 'https://authserver.example/auth'
+ scopes:
+ 'streetlights:on': Ability to switch lights on
+ 'streetlights:off': Ability to switch lights off
+ 'streetlights:dim': Ability to dim the lights
+ password:
+ tokenUrl: 'https://authserver.example/token'
+ scopes:
+ 'streetlights:on': Ability to switch lights on
+ 'streetlights:off': Ability to switch lights off
+ 'streetlights:dim': Ability to dim the lights
+ clientCredentials:
+ tokenUrl: 'https://authserver.example/token'
+ scopes:
+ 'streetlights:on': Ability to switch lights on
+ 'streetlights:off': Ability to switch lights off
+ 'streetlights:dim': Ability to dim the lights
+ authorizationCode:
+ authorizationUrl: 'https://authserver.example/auth'
+ tokenUrl: 'https://authserver.example/token'
+ refreshUrl: 'https://authserver.example/refresh'
+ scopes:
+ 'streetlights:on': Ability to switch lights on
+ 'streetlights:off': Ability to switch lights off
+ 'streetlights:dim': Ability to dim the lights
+ openIdConnectWellKnown:
+ type: openIdConnect
+ openIdConnectUrl: 'https://authserver.example/.well-known'
+
+ parameters:
+ streetlightId:
+ description: The ID of the streetlight.
+ schema:
+ type: string
+
+ messageTraits:
+ commonHeaders:
+ headers:
+ type: object
+ properties:
+ my-app-header:
+ type: integer
+ minimum: 0
+ maximum: 100
+
+ operationTraits:
+ kafka:
+ bindings:
+ kafka:
+ clientId: my-app-id
diff --git a/plugins/api-docs/dev/graphql-example-api.yaml b/plugins/api-docs/dev/graphql-example-api.yaml
new file mode 100644
index 0000000000..f3d924fc53
--- /dev/null
+++ b/plugins/api-docs/dev/graphql-example-api.yaml
@@ -0,0 +1,1180 @@
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: starwars-graphql
+ description: SWAPI GraphQL Schema
+ links:
+ - url: https://github.com/graphql/swapi-graphql
+ title: GitHub Repo
+ icon: github
+spec:
+ type: graphql
+ lifecycle: production
+ owner: team-b
+ definition: |
+ schema {
+ query: Root
+ }
+
+ """A single film."""
+ type Film implements Node {
+ """The title of this film."""
+ title: String
+
+ """The episode number of this film."""
+ episodeID: Int
+
+ """The opening paragraphs at the beginning of this film."""
+ openingCrawl: String
+
+ """The name of the director of this film."""
+ director: String
+
+ """The name(s) of the producer(s) of this film."""
+ producers: [String]
+
+ """The ISO 8601 date format of film release at original creator country."""
+ releaseDate: String
+ speciesConnection(after: String, first: Int, before: String, last: Int): FilmSpeciesConnection
+ starshipConnection(after: String, first: Int, before: String, last: Int): FilmStarshipsConnection
+ vehicleConnection(after: String, first: Int, before: String, last: Int): FilmVehiclesConnection
+ characterConnection(after: String, first: Int, before: String, last: Int): FilmCharactersConnection
+ planetConnection(after: String, first: Int, before: String, last: Int): FilmPlanetsConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type FilmCharactersConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmCharactersEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ characters: [Person]
+ }
+
+ """An edge in a connection."""
+ type FilmCharactersEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type FilmPlanetsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmPlanetsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ planets: [Planet]
+ }
+
+ """An edge in a connection."""
+ type FilmPlanetsEdge {
+ """The item at the end of the edge"""
+ node: Planet
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type FilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type FilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type FilmSpeciesConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmSpeciesEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ species: [Species]
+ }
+
+ """An edge in a connection."""
+ type FilmSpeciesEdge {
+ """The item at the end of the edge"""
+ node: Species
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type FilmStarshipsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmStarshipsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ starships: [Starship]
+ }
+
+ """An edge in a connection."""
+ type FilmStarshipsEdge {
+ """The item at the end of the edge"""
+ node: Starship
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type FilmVehiclesConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [FilmVehiclesEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ vehicles: [Vehicle]
+ }
+
+ """An edge in a connection."""
+ type FilmVehiclesEdge {
+ """The item at the end of the edge"""
+ node: Vehicle
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """An object with an ID"""
+ interface Node {
+ """The id of the object."""
+ id: ID!
+ }
+
+ """Information about pagination in a connection."""
+ type PageInfo {
+ """When paginating forwards, are there more items?"""
+ hasNextPage: Boolean!
+
+ """When paginating backwards, are there more items?"""
+ hasPreviousPage: Boolean!
+
+ """When paginating backwards, the cursor to continue."""
+ startCursor: String
+
+ """When paginating forwards, the cursor to continue."""
+ endCursor: String
+ }
+
+ """A connection to a list of items."""
+ type PeopleConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PeopleEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ people: [Person]
+ }
+
+ """An edge in a connection."""
+ type PeopleEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """An individual person or character within the Star Wars universe."""
+ type Person implements Node {
+ """The name of this person."""
+ name: String
+
+ """
+ The birth year of the person, using the in-universe standard of BBY or ABY -
+ Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is
+ a battle that occurs at the end of Star Wars episode IV: A New Hope.
+ """
+ birthYear: String
+
+ """
+ The eye color of this person. Will be "unknown" if not known or "n/a" if the
+ person does not have an eye.
+ """
+ eyeColor: String
+
+ """
+ The gender of this person. Either "Male", "Female" or "unknown",
+ "n/a" if the person does not have a gender.
+ """
+ gender: String
+
+ """
+ The hair color of this person. Will be "unknown" if not known or "n/a" if the
+ person does not have hair.
+ """
+ hairColor: String
+
+ """The height of the person in centimeters."""
+ height: Int
+
+ """The mass of the person in kilograms."""
+ mass: Float
+
+ """The skin color of this person."""
+ skinColor: String
+
+ """A planet that this person was born on or inhabits."""
+ homeworld: Planet
+ filmConnection(after: String, first: Int, before: String, last: Int): PersonFilmsConnection
+
+ """The species that this person belongs to, or null if unknown."""
+ species: Species
+ starshipConnection(after: String, first: Int, before: String, last: Int): PersonStarshipsConnection
+ vehicleConnection(after: String, first: Int, before: String, last: Int): PersonVehiclesConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type PersonFilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PersonFilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type PersonFilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type PersonStarshipsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PersonStarshipsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ starships: [Starship]
+ }
+
+ """An edge in a connection."""
+ type PersonStarshipsEdge {
+ """The item at the end of the edge"""
+ node: Starship
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type PersonVehiclesConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PersonVehiclesEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ vehicles: [Vehicle]
+ }
+
+ """An edge in a connection."""
+ type PersonVehiclesEdge {
+ """The item at the end of the edge"""
+ node: Vehicle
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """
+ A large mass, planet or planetoid in the Star Wars Universe, at the time of
+ 0 ABY.
+ """
+ type Planet implements Node {
+ """The name of this planet."""
+ name: String
+
+ """The diameter of this planet in kilometers."""
+ diameter: Int
+
+ """
+ The number of standard hours it takes for this planet to complete a single
+ rotation on its axis.
+ """
+ rotationPeriod: Int
+
+ """
+ The number of standard days it takes for this planet to complete a single orbit
+ of its local star.
+ """
+ orbitalPeriod: Int
+
+ """
+ A number denoting the gravity of this planet, where "1" is normal or 1 standard
+ G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs.
+ """
+ gravity: String
+
+ """The average population of sentient beings inhabiting this planet."""
+ population: Float
+
+ """The climates of this planet."""
+ climates: [String]
+
+ """The terrains of this planet."""
+ terrains: [String]
+
+ """
+ The percentage of the planet surface that is naturally occuring water or bodies
+ of water.
+ """
+ surfaceWater: Float
+ residentConnection(after: String, first: Int, before: String, last: Int): PlanetResidentsConnection
+ filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type PlanetFilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PlanetFilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type PlanetFilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type PlanetResidentsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PlanetResidentsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ residents: [Person]
+ }
+
+ """An edge in a connection."""
+ type PlanetResidentsEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type PlanetsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [PlanetsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ planets: [Planet]
+ }
+
+ """An edge in a connection."""
+ type PlanetsEdge {
+ """The item at the end of the edge"""
+ node: Planet
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ type Root {
+ allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection
+ film(id: ID, filmID: ID): Film
+ allPeople(after: String, first: Int, before: String, last: Int): PeopleConnection
+ person(id: ID, personID: ID): Person
+ allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection
+ planet(id: ID, planetID: ID): Planet
+ allSpecies(after: String, first: Int, before: String, last: Int): SpeciesConnection
+ species(id: ID, speciesID: ID): Species
+ allStarships(after: String, first: Int, before: String, last: Int): StarshipsConnection
+ starship(id: ID, starshipID: ID): Starship
+ allVehicles(after: String, first: Int, before: String, last: Int): VehiclesConnection
+ vehicle(id: ID, vehicleID: ID): Vehicle
+
+ """Fetches an object given its ID"""
+ node(
+ """The ID of an object"""
+ id: ID!
+ ): Node
+ }
+
+ """A type of person or character within the Star Wars Universe."""
+ type Species implements Node {
+ """The name of this species."""
+ name: String
+
+ """The classification of this species, such as "mammal" or "reptile"."""
+ classification: String
+
+ """The designation of this species, such as "sentient"."""
+ designation: String
+
+ """The average height of this species in centimeters."""
+ averageHeight: Float
+
+ """The average lifespan of this species in years, null if unknown."""
+ averageLifespan: Int
+
+ """
+ Common eye colors for this species, null if this species does not typically
+ have eyes.
+ """
+ eyeColors: [String]
+
+ """
+ Common hair colors for this species, null if this species does not typically
+ have hair.
+ """
+ hairColors: [String]
+
+ """
+ Common skin colors for this species, null if this species does not typically
+ have skin.
+ """
+ skinColors: [String]
+
+ """The language commonly spoken by this species."""
+ language: String
+
+ """A planet that this species originates from."""
+ homeworld: Planet
+ personConnection(after: String, first: Int, before: String, last: Int): SpeciesPeopleConnection
+ filmConnection(after: String, first: Int, before: String, last: Int): SpeciesFilmsConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type SpeciesConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [SpeciesEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ species: [Species]
+ }
+
+ """An edge in a connection."""
+ type SpeciesEdge {
+ """The item at the end of the edge"""
+ node: Species
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type SpeciesFilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [SpeciesFilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type SpeciesFilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type SpeciesPeopleConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [SpeciesPeopleEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ people: [Person]
+ }
+
+ """An edge in a connection."""
+ type SpeciesPeopleEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A single transport craft that has hyperdrive capability."""
+ type Starship implements Node {
+ """The name of this starship. The common name, such as "Death Star"."""
+ name: String
+
+ """
+ The model or official name of this starship. Such as "T-65 X-wing" or "DS-1
+ Orbital Battle Station".
+ """
+ model: String
+
+ """
+ The class of this starship, such as "Starfighter" or "Deep Space Mobile
+ Battlestation"
+ """
+ starshipClass: String
+
+ """The manufacturers of this starship."""
+ manufacturers: [String]
+
+ """The cost of this starship new, in galactic credits."""
+ costInCredits: Float
+
+ """The length of this starship in meters."""
+ length: Float
+
+ """The number of personnel needed to run or pilot this starship."""
+ crew: String
+
+ """The number of non-essential people this starship can transport."""
+ passengers: String
+
+ """
+ The maximum speed of this starship in atmosphere. null if this starship is
+ incapable of atmosphering flight.
+ """
+ maxAtmospheringSpeed: Int
+
+ """The class of this starships hyperdrive."""
+ hyperdriveRating: Float
+
+ """
+ The Maximum number of Megalights this starship can travel in a standard hour.
+ A "Megalight" is a standard unit of distance and has never been defined before
+ within the Star Wars universe. This figure is only really useful for measuring
+ the difference in speed of starships. We can assume it is similar to AU, the
+ distance between our Sun (Sol) and Earth.
+ """
+ MGLT: Int
+
+ """The maximum number of kilograms that this starship can transport."""
+ cargoCapacity: Float
+
+ """
+ The maximum length of time that this starship can provide consumables for its
+ entire crew without having to resupply.
+ """
+ consumables: String
+ pilotConnection(after: String, first: Int, before: String, last: Int): StarshipPilotsConnection
+ filmConnection(after: String, first: Int, before: String, last: Int): StarshipFilmsConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type StarshipFilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [StarshipFilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type StarshipFilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type StarshipPilotsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [StarshipPilotsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ pilots: [Person]
+ }
+
+ """An edge in a connection."""
+ type StarshipPilotsEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type StarshipsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [StarshipsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ starships: [Starship]
+ }
+
+ """An edge in a connection."""
+ type StarshipsEdge {
+ """The item at the end of the edge"""
+ node: Starship
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A single transport craft that does not have hyperdrive capability"""
+ type Vehicle implements Node {
+ """
+ The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder
+ bike".
+ """
+ name: String
+
+ """
+ The model or official name of this vehicle. Such as "All-Terrain Attack
+ Transport".
+ """
+ model: String
+
+ """The class of this vehicle, such as "Wheeled" or "Repulsorcraft"."""
+ vehicleClass: String
+
+ """The manufacturers of this vehicle."""
+ manufacturers: [String]
+
+ """The cost of this vehicle new, in Galactic Credits."""
+ costInCredits: Float
+
+ """The length of this vehicle in meters."""
+ length: Float
+
+ """The number of personnel needed to run or pilot this vehicle."""
+ crew: String
+
+ """The number of non-essential people this vehicle can transport."""
+ passengers: String
+
+ """The maximum speed of this vehicle in atmosphere."""
+ maxAtmospheringSpeed: Int
+
+ """The maximum number of kilograms that this vehicle can transport."""
+ cargoCapacity: Float
+
+ """
+ The maximum length of time that this vehicle can provide consumables for its
+ entire crew without having to resupply.
+ """
+ consumables: String
+ pilotConnection(after: String, first: Int, before: String, last: Int): VehiclePilotsConnection
+ filmConnection(after: String, first: Int, before: String, last: Int): VehicleFilmsConnection
+
+ """The ISO 8601 date format of the time that this resource was created."""
+ created: String
+
+ """The ISO 8601 date format of the time that this resource was edited."""
+ edited: String
+
+ """The ID of an object"""
+ id: ID!
+ }
+
+ """A connection to a list of items."""
+ type VehicleFilmsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [VehicleFilmsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ films: [Film]
+ }
+
+ """An edge in a connection."""
+ type VehicleFilmsEdge {
+ """The item at the end of the edge"""
+ node: Film
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type VehiclePilotsConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [VehiclePilotsEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ pilots: [Person]
+ }
+
+ """An edge in a connection."""
+ type VehiclePilotsEdge {
+ """The item at the end of the edge"""
+ node: Person
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
+
+ """A connection to a list of items."""
+ type VehiclesConnection {
+ """Information to aid in pagination."""
+ pageInfo: PageInfo!
+
+ """A list of edges."""
+ edges: [VehiclesEdge]
+
+ """
+ A count of the total number of objects in this connection, ignoring pagination.
+ This allows a client to fetch the first five objects by passing "5" as the
+ argument to "first", then fetch the total count so it could display "5 of 83",
+ for example.
+ """
+ totalCount: Int
+
+ """
+ A list of all of the objects returned in the connection. This is a convenience
+ field provided for quickly exploring the API; rather than querying for
+ "{ edges { node } }" when no edge data is needed, this field can be be used
+ instead. Note that when clients like Relay need to fetch the "cursor" field on
+ the edge to enable efficient pagination, this shortcut cannot be used, and the
+ full "{ edges { node } }" version should be used instead.
+ """
+ vehicles: [Vehicle]
+ }
+
+ """An edge in a connection."""
+ type VehiclesEdge {
+ """The item at the end of the edge"""
+ node: Vehicle
+
+ """A cursor for use in pagination"""
+ cursor: String!
+ }
diff --git a/plugins/api-docs/dev/index.tsx b/plugins/api-docs/dev/index.tsx
index 4bf0215f32..fbfab37f5b 100644
--- a/plugins/api-docs/dev/index.tsx
+++ b/plugins/api-docs/dev/index.tsx
@@ -14,11 +14,21 @@
* limitations under the License.
*/
-import React from 'react';
+import { ApiEntity, Entity } from '@backstage/catalog-model';
+import { Content, Header, Page } from '@backstage/core';
import { createDevApp } from '@backstage/dev-utils';
-import { ApiExplorerPage, apiDocsPlugin } from '../src/plugin';
-import { catalogApiRef } from '@backstage/plugin-catalog-react';
-import petstoreApiEntity from './example-api.yaml';
+import { catalogApiRef, EntityProvider } from '@backstage/plugin-catalog-react';
+import React from 'react';
+import {
+ apiDocsConfigRef,
+ ApiExplorerPage,
+ defaultDefinitionWidgets,
+ EntityApiDefinitionCard,
+} from '../src';
+import asyncapiApiEntity from './asyncapi-example-api.yaml';
+import graphqlApiEntity from './graphql-example-api.yaml';
+import openapiApiEntity from './openapi-example-api.yaml';
+import otherApiEntity from './other-example-api.yaml';
createDevApp()
.registerApi({
@@ -27,10 +37,80 @@ createDevApp()
factory: () =>
(({
async getEntities() {
- return { items: [petstoreApiEntity] };
+ return {
+ items: [
+ openapiApiEntity,
+ asyncapiApiEntity,
+ graphqlApiEntity,
+ otherApiEntity,
+ ],
+ };
},
} as unknown) as typeof catalogApiRef.T),
})
- .registerPlugin(apiDocsPlugin)
- .addPage({ element: })
+ .registerApi({
+ api: apiDocsConfigRef,
+ deps: {},
+ factory: () => {
+ const definitionWidgets = defaultDefinitionWidgets();
+ return {
+ getApiDefinitionWidget: (apiEntity: ApiEntity) => {
+ return definitionWidgets.find(d => d.type === apiEntity.spec.type);
+ },
+ };
+ },
+ })
+ .addPage({ title: 'API Explorer', element: })
+ .addPage({
+ title: 'OpenAPI',
+ element: (
+
+
+
+
+
+
+
+
+ ),
+ })
+ .addPage({
+ title: 'AsyncAPI',
+ element: (
+
+
+
+
+
+
+
+
+ ),
+ })
+ .addPage({
+ title: 'GraphQL',
+ element: (
+
+
+
+
+
+
+
+
+ ),
+ })
+ .addPage({
+ title: 'Other',
+ element: (
+
+
+
+
+
+
+
+
+ ),
+ })
.render();
diff --git a/plugins/api-docs/dev/example-api.yaml b/plugins/api-docs/dev/openapi-example-api.yaml
similarity index 100%
rename from plugins/api-docs/dev/example-api.yaml
rename to plugins/api-docs/dev/openapi-example-api.yaml
diff --git a/plugins/api-docs/dev/other-example-api.yaml b/plugins/api-docs/dev/other-example-api.yaml
new file mode 100644
index 0000000000..0f9786329f
--- /dev/null
+++ b/plugins/api-docs/dev/other-example-api.yaml
@@ -0,0 +1,48 @@
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: hello-world
+ description: Hello World example for gRPC
+spec:
+ type: grpc
+ lifecycle: deprecated
+ owner: team-c
+ definition: |
+ // Copyright 2015 gRPC authors.
+ //
+ // Licensed under the Apache License, Version 2.0 (the "License");
+ // you may not use this file except in compliance with the License.
+ // You may obtain a copy of the License at
+ //
+ // http://www.apache.org/licenses/LICENSE-2.0
+ //
+ // Unless required by applicable law or agreed to in writing, software
+ // distributed under the License is distributed on an "AS IS" BASIS,
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ // See the License for the specific language governing permissions and
+ // limitations under the License.
+
+ syntax = "proto3";
+
+ option java_multiple_files = true;
+ option java_package = "io.grpc.examples.helloworld";
+ option java_outer_classname = "HelloWorldProto";
+ option objc_class_prefix = "HLW";
+
+ package helloworld;
+
+ // The greeting service definition.
+ service Greeter {
+ // Sends a greeting
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+ }
+
+ // The request message containing the user's name.
+ message HelloRequest {
+ string name = 1;
+ }
+
+ // The response message containing the greetings
+ message HelloReply {
+ string message = 1;
+ }
diff --git a/plugins/api-docs/src/index.ts b/plugins/api-docs/src/index.ts
index 8bab7f28f4..720183e1cd 100644
--- a/plugins/api-docs/src/index.ts
+++ b/plugins/api-docs/src/index.ts
@@ -15,6 +15,7 @@
*/
export * from './components';
+export { apiDocsConfigRef } from './config';
export {
apiDocsPlugin,
apiDocsPlugin as plugin,
@@ -22,7 +23,7 @@ export {
EntityApiDefinitionCard,
EntityConsumedApisCard,
EntityConsumingComponentsCard,
+ EntityHasApisCard,
EntityProvidedApisCard,
EntityProvidingComponentsCard,
- EntityHasApisCard,
} from './plugin';
diff --git a/yarn.lock b/yarn.lock
index 16e5a9686e..73aba4a93a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1978,6 +1978,7 @@
"@backstage/catalog-client" "^0.3.8"
"@backstage/catalog-model" "^0.7.4"
"@backstage/core" "^0.7.3"
+ "@backstage/errors" "^0.1.1"
"@backstage/integration" "^0.5.1"
"@backstage/integration-react" "^0.1.1"
"@backstage/plugin-catalog-react" "^0.1.3"
@@ -2002,6 +2003,7 @@
"@backstage/catalog-client" "^0.3.8"
"@backstage/catalog-model" "^0.7.4"
"@backstage/core" "^0.7.3"
+ "@backstage/errors" "^0.1.1"
"@backstage/integration" "^0.5.1"
"@backstage/integration-react" "^0.1.1"
"@backstage/plugin-catalog-react" "^0.1.3"