Create ApiDocs
Create ApiDocs that have the OpenAPI spec of your backing services.
To identify the OpenAPI spec for all of the API services in your environment, Gloo uses an ApiDoc custom resource.
Before you begin
For example steps, see the Set up Gloo Portal tutorial.
- Install Gloo Portal.
- Deploy REST API services that conform to the OpenAPI specification (OAS), v2 or v3.
Options to create ApiDocs
To create ApiDocs, choose from the options in the following table.
Method | ApiDoc creation | How to trigger updates to ApiDoc | Description |
---|---|---|---|
Kubernetes service annotations | Automatic | Update the Kubernetes service | Add annotations to your apps’ services so that Gloo automatically discovers their REST APIs. |
ApiSchemaDiscovery | Automatic | Delete and recreate the ApiSchemaDiscovery | Create an ApiSchemaDiscovery custom resource with a URL endpoint to your API schema. Then, Gloo fetches the API schema from the URL and automatically creates an ApiDoc for you. |
ApiDoc | Manual | Update the ApiDoc manually | Manually create a Gloo ApiDoc custom resource to describe your REST API services. Typically, you choose this option if you use external services for apps that run outside your cluster environment, such as in a virtual machine (VM). |
Automatically discover REST API services
Annotate your Kubernetes services so that Gloo automatically discovers their REST API services and creates the ApiDoc resource for you. Any time that you redeploy your workloads, Gloo refetches the OpenAPI spec to update the ApiDoc for you.
You can create an ApiSchemaDiscovery resource instead if:
- You do not want to annotate your services.
- Your service does not expose the OpenAPI schema along a path.
To annotate your services:
Review or update the
gloo.solo.io
annotations that Gloo used to automatically discover and create an ApiDoc for each service.Review the following table to understand this configuration.
Setting Required? Description /scrape-openapi-source
Yes Add the relative path where your service exposes its OpenAPI v2 or v3 specification in YAML or JSON format. Common paths include /api/v3/openapi.json
or/swagger.json
. You might also provide a publicly accessible URL to the spec, such as Istio’s bookinfo example:https://raw.githubusercontent.com/istio/istio/master/samples/bookinfo/swagger.yaml
./scrape-openapi-scheme
No Enter http
orhttps
for the protocol scheme to use when accessing the OpenAPI schema, such as if it differs from the source endpoint. The default value ishttp
./scrape-openapi-port
No Enter the port to use when accessing the OpenAPI schema, such as if it differs from the source endpoint. /scrape-openapi-pull-attempts
,/scrape-openapi-retry-delay
,/scrape-openapi-use-backoff
No You can configure these annotations for increased resiliency. For example, if your workload’s container takes some time to spin up, you might adjust the retry delay or the number of pull attempts.
Discover API schema from a URL
Create an ApiSchemaDiscovery custom resource so that Gloo automatically discovers your API schema. You configure the URL endpoint to fetch the OpenAPI schema from, as well as the target destination that serves the OpenAPI schema, such as a Kubernetes service or Gloo virtual destination in the same cluster.
After discovering the OpenAPI schema, the Gloo agent automatically generates an ApiDoc resource. To refresh the OpenAPI schema, you can delete and recreate the ApiSchemaDiscovery.
The following example:
- Pulls an OpenAPI
schema.json
file from thehttps://example.com/tracks-schema.json
URL. Forhttps
, make sure that the URL is included in the certificate that validates the HTTPS traffic. - Specifies that the
tracks-rest-api
Kubernetes service in the same cluster as the ApiSchemaDiscovery resource serves the OpenAPI schema. In multicluster scenarios, this cluster is usually the workload cluster.
You can also set configuration options such as retry, pull, and backoff settings for fetching.
kubectl apply -f - << EOF
apiVersion: portal.gloo.solo.io/v1
kind: ApiSchemaDiscovery
metadata:
name: tracks-api-schema
namespace: tracks
spec:
openapi:
fetchEndpoint:
url: "https://example.com/tracks-schema.json"
servedBy:
- targetRef:
kind: SERVICE
name: tracks-rest-api
namespace: tracks
port: 5000
EOF
Next, verify that your ApiDocs are created.
Manually create an ApiDoc resource
If you don’t want Gloo to automatically discover and create ApiDocs for your apps, you can manually create the ApiDoc resource. You might choose this option if you use external services for apps that run outside your cluster environment, such as in a virtual machine (VM).
Deploy your apps with REST API services that conform to the OpenAPI specification (OAS).
Get the OpenAPI schema for the apps that you deployed.
Create the ApiDoc custom resource to describe the OpenAPI schema of your app.
kubectl apply -f - << EOF apiVersion: portal.gloo.solo.io/v1 kind: ApiDoc metadata: name: customers-api-schema namespace: default spec: openapi: # The YAML- or JSON-formatted OpenAPI v2 or v3 schema string to use for your API. inlineString: '{"components":"customer"}' servedBy: - port: 8080 targetRef: kind: Service name: app namespace: app EOF
Review the following table to understand this configuration.
Setting Description openapi
The YAML- or JSON-formatted OpenAPI v2 or v3 schema string to use for your API. Replace this value with your schema, such as '{ "info": { "title": "Gloo Portal API", "version": "1.0.0", "description": "Review the following reference documentation for the Gloo Portal APIs. Use these endpoints to manage user access to both the developer portal and the API resources exposed by the portal." }, "openapi": "3.0.0", "servers": [ { "url": "https://api.gloo-platform-portal.com/v1" } ], "paths": { "/login": { "get": { "description": "Logs user into the developer portal. This is the path that should be used as the callbackPath in the ExtAuthPolicy's OIDC configuration.", "operationId": "login", "security": [ { "identityToken": [ ] } ], "responses": { "200": { "description": "Successfully logged in" } }, "summary": "Logs user into the developer portal", "tags": [ "User" ] } }'
servedBy
Specify the target reference and port for your app. This target destination matches the destinations that you later route to. Supported destinations are Kubernetes services or Gloo upstreams.
Verify that your ApiDocs are created
Verify that your apps are running and that Gloo has the ApiDocs that describe their OpenAPI specs.
kubectl
, or when viewing the object in the Gloo UI. Unlike other Gloo custom resources, ApiDocs can be both an input and output object. For example, you can manually create an ApiDoc (input), or Gloo can automatically create an ApiDoc during discovery or translation processes (output). As such, status for ApiDocs is disabled. Because the status is disabled, you cannot review statuses for ApiDocs in kubectl
. Also, you might notice ApiDocs reported as unhealthy in the Gloo UI even though the ApiDocs work. To verify that your ApiDocs are healthy, you can follow the steps in the ApiDoc guide.Check that your apps are running.
kubectl get pods -A
Automatic discovery: Enable port-forwarding for one of your apps and check that the OpenAPI spec exists on the path that you included in the
gloo.solo.io/scrape-openapi-source
annotation on the service. The following example checks the Tracks app.kubectl -n tracks port-forward services/tracks-rest-api 5000:5000
In your browser, open
http://localhost:5000/swagger.json
and verify that the OpenAPI spec exists:{ "swagger": "2.0", "info": { "description": "REST API for Catstronauts to retrieve data for tracks, authors and modules.", "version": "1.0.0", "title": "Catstronauts REST API" }, ...
List the ApiDocs in each app’s namespace.
kubectl get apidocs -A
Optional: If an app does not have an ApiDoc, try recreating the service. Or, you can manually create an ApiDoc such as with the following example.
kubectl apply -n tracks -f - << EOF apiVersion: portal.gloo.solo.io/v1 kind: ApiDoc metadata: name: tracks-rest-api-service namespace: tracks spec: openapi: # The YAML- or JSON-formatted OpenAPI v2 or v3 schema string to use for your API. inlineString: '{"openapi":"3.0.3","info":{"title":"Catstronauts REST API","description":"REST API for Catstronauts to retrieve data for tracks, authors and modules.","version":"1.1.0"},"servers":[{"url":"/"}],"tags":[{"name":"Tracks","description":"A track is a collection of modules around a topic for catstronauts to learn about."},{"name":"Authors"},{"name":"Modules"}],"paths":{"/tracks":{"get":{"tags":["Tracks"],"summary":"Retrieves a list of tracks","responses":{"200":{"description":"Successful. Returns an array of Track objects.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Track"}},"examples":{"test-1":{"value":[{"id":"c_0","thumbnail":"https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg","topic":"Cat-stronomy","authorId":"cat-1","title":"Cat-stronomy, an introduction","description":"Curious to learn what Cat-stronomy is all about? Explore the planetary and celestial alignments and how they have affected our space missions.","numberOfViews":163,"createdAt":"2018-09-10T07:13:53.020Z","length":2377,"modulesCount":10,"modules":["l_0","l_1","l_2","l_3","l_4","l_5","l_6","l_7","l_8","l_9"]},{"id":"c_1","thumbnail":"https://res.cloudinary.com/dety84pbu/image/upload/v1598474100/famous_cats_epuqcr.jpg","topic":"Famous Catstronauts","authorId":"cat-2","title":"Famous Catstronauts","description":"Be inspired by famous catstronauts who have made their names legend from across the galaxies. Special guest appearance included, so hold on to your boots!","numberOfViews":86,"createdAt":"2017-12-06T23:03:08.815Z","length":1916,"modulesCount":5,"modules":["l_10","l_11","l_12","l_13","l_14"]}]},"test-2":{"value":[{"id":"c_2","thumbnail":"https://res.cloudinary.com/dety84pbu/image/upload/v1598457117/spaceSuite_knkmu8.jpg","topic":"Kitty space suit","authorId":"cat-3","title":"Kitty space suit, all you need to know","description":"# Fidem dum accipit officio tactaeque extis caecaeque \n ## Caelo scilicet protulit \n Lorem markdownum et naides sumpserat nasci est vulnere mille comitesque \n praeterque crus, cur ruere, per nemus tanta dextra? Dente fluit adspeximus \n dempto, faciem, minimo parentali locorum! Unda an ergo equidem regia hac se est \n ira pugnantem. \n > Invenerit Solem agmine; aut voce melioris Lesbi. Lacrimas ad et, pendens quem, \n > ater venatrixque quis. Sed cacumina tulisti occasus, trisulcis multum, quid. \n > Quam Mercurium tergusque modo ubi, captis reddidit quae posse, rata popularis \n > inferni. \n ## Spatiosumque nigris \n Praemia qua simul fallitur cum et iuppiter inquit adversaque cutem, at dextera, \n alias. Scelus utque dolor, iuncta quamvis, hunc auceps celebrare coetu excussum \n deiectam. Videres nectar utque catenas una Granico corpore, verba Iovis \n intellectumque templum, domum dat et quod. Pedum quod cultusque versus magnorum \n ira ratis coepi conplexibus et armento summa non Dianae, dare ardor adire. \n Carens peperisse; omnem tenus, me sine. \n - Dare prior \n - Est incessit ille mirantum facta fiunt \n - Sed modo deprendit inpediunt sublime quiete \n ## Aeacus carpit hanc vestes senectus pocula \n Et novos esset genetrix glacies; inluxisse protecta, est ante consumptis, \n manumque, Phylius genitore caelarat herbosaque. Phoebus vulnera, clade debita, \n satiantur nefando. \n > Deprensi de velum alas Circaea quies perterrita si mota quam terres, sic si \n > res gerebam viros esse. Medullas ut tenax mandata classe amores vastius siqua, \n > sanabilis sed fiducia Leucon, capaci Orithyiae. Lumen terris digitis ac modo \n > sequentis Cereri te tulerit inspicitur! Subit veneno equi videt genua in \n > aetasque qui sanguisque, mihi flexit vivunt hamadryadas. \n ## At pater gestamina gravi forma \n Nec inter est adopertam nec, supernum et tecta: tapetibus? Genetrix sustinet \n heres pugnae usquam erectos in erant Achilles! \n Fuerat harenae me hiems Pholus tempus Phoebe. Geminis mihi vimen, in vidi \n pigetque in mole cruore, fugat dissuadet!","numberOfViews":61,"createdAt":"2020-04-20T13:59:10.470Z","length":1823,"modulesCount":5,"modules":["l_15","l_16","l_17","l_18","l_19"]}]}}}}}}}},"/tracks/{id}":{"get":{"tags":["Tracks"],"summary":"Find track by ID","description":"Returns a single track","parameters":[{"name":"id","in":"path","description":"Track ID","required":true,"schema":{"type":"string"},"examples":{"c_0":{"value":"c_0"}}}],"responses":{"200":{"description":"Successful. Returns a single track.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Track"},"examples":{"c_0":{"value":{"thumbnail":"https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg","topic":"Cat-stronomy","authorId":"cat-1","title":"Cat-stronomy, an introduction","description":"Curious to learn what Cat-stronomy is all about? Explore the planetary and celestial alignments and how they have affected our space missions.","numberOfViews":163,"createdAt":"2018-09-10T07:13:53.020Z","length":2377,"modulesCount":10,"modules":["l_0","l_1","l_2","l_3","l_4","l_5","l_6","l_7","l_8","l_9"]}}}}}},"404":{"description":"Track not found.","content":{}}}}},"/tracks/{id}/modules":{"get":{"tags":["Tracks"],"summary":"Retrieves the list of modules for a given track","parameters":[{"name":"id","in":"path","description":"Track ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful. Returns the list of modules for a given track.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Module"}}}}},"404":{"description":"Track not found.","content":{}}}}},"/tracks/{id}/numberOfViews":{"patch":{"tags":["Tracks"],"summary":"Updates the number of views for a track","parameters":[{"name":"id","in":"path","description":"Track ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful. Returns the updated Track object.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Track"}}}}},"404":{"description":"Track not found.","content":{}}}}},"/author/{id}":{"get":{"tags":["Authors"],"summary":"Find author by ID","description":"Returns a single author","parameters":[{"name":"id","in":"path","description":"Author ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful. Returns a single author.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Author"}}}},"404":{"description":"Author not found.","content":{}}}}},"/module/{id}":{"get":{"tags":["Modules"],"summary":"Find module by ID","description":"Returns a single module","parameters":[{"name":"id","in":"path","description":"Module ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful. Returns a single module.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Module"}}}},"404":{"description":"Module not found.","content":{}}}}}},"components":{"schemas":{"Track":{"type":"object","properties":{"id":{"type":"string"},"thumbnail":{"type":"string"},"topic":{"type":"string"},"authorId":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"numberOfViews":{"type":"integer"},"createdAt":{"type":"string"},"length":{"type":"integer"},"modulesCount":{"type":"integer"},"modules":{"type":"array","items":{"type":"string"}}}},"Author":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"photo":{"type":"string"}}},"Module":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"trackId":{"type":"string"},"authorId":{"type":"string"},"topic":{"type":"string"},"length":{"type":"integer"},"content":{"type":"string"},"videoUrl":{"type":"string"}}}}}}' servedBy: - destinationSelector: port: 5000 targetRef: kind: Service name: tracks-rest-api namespace: tracks EOF
Describe one of the ApiDocs, and verify that the ApiDoc has the OpenAPI spec for the service.
kubectl describe apidocs -n tracks
Example output:
... Spec: Openapi: Inline String: {"components":{"schemas":{"Author":{"properties":{"id":{"type":"string"},"name":{"type":"string"},"photo":{"type":"string"}},"type":"object"},"Module":{"properties":{"authorId":{"type":"string"},"content":{"type":"string"}