Your own GraphQL Query
We are going to release @farfetched/graphql in the future, until that we suggest you to use @farfetched/core and create your own GraphQL Query factory. In this recipe, we will guide it through this process step-by-step.
Step 0: choose basement
Basically, GraphQL API is a JSON API with additional restrictions, so we can use createJsonQuery to simplify the process. Key differences between it and our custom factory are:
createGraphQLQuerymust follow more strict structure ofbody. It has to contain fieldquerywith the GraphQL query, fieldvariableswith the variables for the query.createGraphQLQuerymust not allow user to pass any search-parameters.createGraphQLQuerymust use onlyPOSTmethod.
INFO
Original createJsonQuery has plenty of different overloads, but it's a bit noisy to implement all of them in this recipe, so we will use pure JavaScript without TypeScript annotations.
Step 1: create factory
Let's create the function which we will be used as a factory of our Queries 👇
function createGraphQLQuery(config) {
const query = createJsonQuery({
// ???
});
return query;
}TIP
Do not forget to add path of the factory to a factories list in the code transformations configuration.
Now, we have to write code with mapping from config of createGraphQLQuery to config of createJsonQuery.
Step 2: transform config
As we discussed earlier, we have to override only some fields in the request, others can be passed as is.
function createGraphQLQuery(config) {
const query = createJsonQuery({
...config,
request: {
...config.request,
method: /* ??? */,
query: /* ??? */,
body: /* ??? */,
},
});
return query;
}So, let's start with easy parts: define request.method as POST in any case and clean request.query due to the GraphQL restrictions.
function createGraphQLQuery(config) {
const query = createJsonQuery({
...config,
request: {
...config.request,
method: 'POST',
query: {},
body: /* ??? */,
},
});
return query;
}Our next step is request.body overriding. Let's assume, that we want to provide interface of our factory the same with createJsonQuery, so allow passing only static string as request.graphQL.query and function of parameters as request.graphQL.variables.
const countriesQuery = createGraphQLQuery({
request: {
graphQL: {
// query is static string
query: `
query Countries($language: String!, $fallback: String!) {
countries {
iata
translations(filter: { locales: [$language, $fallback] })
}
}`,
// variables is function of parameters
variables: (params) => ({
language: params.lang,
}),
},
},
});So, let's formulate request.body based on these parameters:
function createGraphQLQuery(config) {
const query = createJsonQuery({
...config,
request: {
...config.request,
method: 'POST',
query: {},
body: (params) => ({
query: request.graphQL.query,
variables: request.graphQL.variables(params))
}),
},
});
return query;
}Step 3: enjoy
That is all, we have a ready-to-use factory createGraphQLQuery. Returned Query is a simple Query, it can be used in the same way as any other Query.
// Query is created by built-in factory
const languageQuery = createJsonQuery({
request: {
url: '/api/language',
method: 'GET',
},
response: { mapData: ({ result }) => result.language.code },
});
// Query is created by custom factory
const countriesQuery = createGraphQLQuery({
request: {
url: '/api/graphql',
graphQL: {
query: `
query Countries($language: String!) {
countries {
iata
translations(filter: { locales: [$language] })
}
}`,
variables: (params) => ({
language: params.language,
}),
},
},
response: { mapData: ({ result }) => result.countries },
});
// They can be used together
connectQuery({
source: languageQuery,
fn({ result: language }) {
return { params: { language } };
},
target: countriesQuery,
});INFO
Of course, there are a lot of improvements to be done like schema introspection, contract generation, etc. We will introduce it in v0.4.