Integrating an app with a GraphQL API
Learn how to query GraphQL APIs from an app.
When developing a VTEX IO app, you may need to interact with other apps that expose GraphQL APIs, such as retrieving data or triggering actions. To do this, you must implement a custom client that handles authenticated requests to the target app.
Once registered with the VTEX IO clients pattern (IOClients
), the client becomes available throughout your app. You can then call it directly from resolvers or middleware functions to integrate external GraphQL capabilities into your service app.
Before you begin
Ensure you meet the technical requirements to follow this guide:
- VTEX IO CLI is installed on your computer.
- Access to a VTEX store with a development workspace and the Admin environment.
- Familiarity with GraphQL concepts, such as queries, schema, and resolvers.
- Experience developing in the TypeScript language.
Implementation
1. Starting with a template
We recommend cloning a VTEX IO app template to your computer if you are developing an app from scratch. In this tutorial, we will use the service-example template. Clone the repository using the following command in a terminal:
_10git clone https://github.com/vtex-apps/service-example
2. Implementing your custom client
VTEX IO provides AppGraphQLClient
as a base class for making GraphQL requests between apps. Your custom client should extend this class, specifying the target app, which exposes the GraphQL API, in the super
constructor. In this class, you must also define the methods you want to use in your middleware functions or resolvers.
In the following example, we define a client that uses the Messages app's translate
query for string translations.
Some details about this implementation:
- Target app: In the client's constructor, define the app you want to query using the format
{vendor}.{app-name}@{version}
. In this example, we usevtex.messages@1
, specifying only the app's major version. You can also specify the exact version with minor and patch values (for example,vtex.messages@1.0.0
). In this constructor, you can include other options in theoptions
parameter, such as authentication tokens in the headers for authenticated queries. - Client functions: Create functions for each query and mutation you need. This example shows a simplified implementation to call the
translate
query. To make the query, use the functionthis.graphql.query
with the following arguments:query
: Insert the query here in a template string format, surrounded by backticks (`
), which allows multi-line separation and usage of variables. In this example, we declare the GraphQL objectGetTranslation
and use the$args
variable as input. Notice that query variables start with the$
symbol. You must use the same names for the queries and variables as in the schema definition. Here we use thetranslate
query and theTranslateArgs!
type for the variable$args
. You can find the type names in the app documentation (for example, Messages GraphQL API), using an Introspection Query, or, if you have access, in the app's source code.variables
: Insert the query variables here as an object, where the property keys are the variable names in the query. In this example,variables.args
is used as the variable$args
in the query.
If you want to use mutations, use the function
this.graphql.mutate
and insert the template string as themutate
argument's value.
3. Registering the client
After you implement the client, register it in your app's list of clients. This step makes the client available in the context of your app's resolvers. To do this, open the node/clients/index.ts
file, import your client, and add it to the Clients
class, as shown in the following example:
4. Using the client
You can now use your custom client to request the target app from your app's handler functions by accessing it via context (ctx.clients
).
In this example, we implement a REST API to access the translation query from the Messages app.
5. Defining the service route
We need to define a route, as we are implementing a REST API to access the middleware. Go to the node/service.json
file, define a public route with the name of the middleware function, and set the path using the format "/_v/{app-name}/{middleware-name}"
. For this implementation, we use:
6. Relating a route to a middleware
Update the node/index.ts
file to relate a route to a middleware. The routes section associates the translateMessages
route with the translateMessages
middleware function. The POST
method is mapped to the translateMessages
function. We use the POST
method as we will send the content to be translated in the request body.
Therefore, when a POST
request is made to the previously defined translateMessages
route, it triggers the translateMessages
function, which, in turn, executes the TranslationGraphQL
client's translate
method.
7. Add the policies
For your app to have permission to access any external resource, you must declare the related policies in your app's manifest.json
file. In the case of a GraphQL API from another app, this is a role-based policy, so you must add the app name and policy name. You can find the policy name and description in the policies.json
file from the app's source code.
Here is the role-based policy from the Messages app for its GraphQL API:
Add the policy to your app using the format "name": "{vendor}.{app-name}:{policy-name}"
. For the Messages app example, we use:
8. Link your app
To test your app, link it to the VTEX platform to enable it to run and accept requests.
Open a terminal and switch to a development workspace. Then, use the vtex link
command.
9. Test your integration
With your app running, you can test the implemented integration. In our example, we implement a REST API in a service app linked to a middleware function. Therefore, we will call the endpoint that executes this function, which invokes the translation query.
Here is a cURL example to call the translation endpoint:
_10curl --request post \_10 --url 'https://{{workspace}}--{{accountname}}.myvtex.com/_v/graphql-integration/translateMessages' \_10 --header 'Accept: application/json' \_10 --header 'Content-Type: application/json' \_10 --header 'VtexIdclientAutCookie: {{vtex-cookie}}' \_10 --data '{"from": "en-US", "messages": [{"content": "shoe"}, {"content": "ball"}], "to": "pt-BR"}'
And we get the following response:
_10{_10 "data": {_10 "translate": [_10 "sapato",_10 "bola"_10 ]_10 }_10}