An API gateway is a component on our application that provides a centralized handling of API communication between the client and the multiple required services.
The API gateway can be implemented via GraphQL Persisted Queries stored in the server and invoked by the client, which interact with one or more backend services, gathering the results and delivering them back to the client in a single response.
These are some benefits of using GraphQL Persisted Queries to provide an API gateway:
Clients do not need to handle connections to backend services, thus simplifying their logic
Access to backend services is centralized
No credentials are exposed on the client
The response from the service can be transformed into what the client expects or can handle better
If some backend service is upgraded, the Persisted Query could be adapted without producing breaking changes in the client
The server can store logs of access to the backend services, and extract metrics to enhance analytics
This tutorial lesson demonstrates an API gateway that retrieves the latest artifacts from the GitHub Actions API, and extracts their URL to be downloaded, avoiding the need for the client to be signed in to GitHub.
The GraphQL query below must be stored as a Persisted Query (for instance, using slug retrieve-public-urls-for-github-actions-artifacts).
It retrieves the publicly-accessible download URLs for GitHub Actions artifacts:
It first fetches the latest X number of artifacts from GitHub Actions, and extracts the proxy URL to access each of them. (Because only authenticated users can access the artifacts, these URLs do not point to the actual artifact yet.)
It then accesses each of these proxy URLs (which has the artifact uploaded to a public location for a short period of time) and extracts the actual URL from the HTTP response's Location header
Finally it prints all publicly-accessible URLs, allowing non-authenticated users to download GitHub artifacts within that window of time
(The tutorial lesson ends here, but as a continuation, the GraphQL query could then do something with these URLs: send them by email, upload the files by FTP somewhere, install them in an InstaWP site, etc.)
We can also allow our users to provide their own GitHub credentials via header.
This GraphQL query is an adaptation of the previous one, with the following differences:
Operation RetrieveGitHubAccessToken reads and exports the value from the current HTTP request's X-Github-Access-Token header, and indicates if this header has not been provided
FailIfGitHubAccessTokenIsMissing triggers an error when the header is missing
All other operations have been added directive @skip(if: $isGithubAccessTokenMissing), so that they will not be executed the the token is missing
When the header X-Github-Access-Token is provided, the response is the same as above.
When it is not provided, the response will be:
We can retrieve from headers the credentials for multiple services used in the API gateway, while validating that they have all been provided:
Below is the detailed analysis of how the query works.
The endpoint to connect to can be dynamically generated, in this case using _sprintf:
The response from the GitHub Actions API is bulky and of no interest to us, so we @remove it from the response. However, during development, we disable this directive, as to visualize and understand the shape of the returned JSON object, and identify the data items we need to extract:
The response is:
The data item of our interest is property "archive_download_url". We navigate to each of these data items within the JSON object structure, extract that value using field _objectProperty (applied via directive @applyField), and override the iterated-upon element by passing argument setResultInResponse: true:
We connect to all the extracted artifact URLs simultaneously via field _sendHTTPRequests (sending the multiple HTTP requests asynchronously), and we query the Location header from each response.
As field _sendHTTPRequests receives argument input (of type [HTTPRequestInput]), we dynamically generate this input, by:
Iterating each of the artifact URLs (stored under dynamic variable $gitHubProxyArtifactDownloadURLs)
Dynamically building a JSON object for each of them (using field _objectAddEntry) that contains all the required parameters (headers, authentication, and others)
Appending the URL to this JSON object (available under dynamic variable $url)
This list of dynamically-created JSON objects will be coerced to [HTTPRequestInput] when passed as argument to _sendHTTPRequests(input:). If our procedure was not right, and any item cannot be coerced to HTTPRequestInput (eg: because we did not provide a mandatory property, or provide a non-existing property), then the GraphQL server will produce a coercion error.
Notice that we must @remove field httpRequestInputs, as it contains the GitHub token (under password: $githubAccessToken), which we do not want to print in the response. During development, though, we can disable this directive.
As @remove is now commented out, we can now visualize the generated JSON object inputs in the response (under entry httpRequestInputs), and then the resulting Location header from each HTTP response (under alias artifactDownloadURL):
Finally we print all the artifactDownloadURL items together as a list (available under dynamic variable $artifactDownloadURLs), using _echo: