Lição 25: Transformando dados de uma API externa
Esta lição do tutorial demonstra exemplos de adaptação da resposta de uma API externa para qualquer formato necessário.
Adicionando valores padrão e propriedades extras a cada entrada
O endpoint da API REST newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url produz dados de usuários, com alguns usuários tendo a propriedade url vazia:
[
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com"
},
{
"id": 7,
"name": "Test",
"url": ""
},
{
"id": 2,
"name": "Theme Demos",
"url": ""
}
]A query GraphQL abaixo transforma esta resposta:
- Adicionando uma URL padrão para os usuários cuja propriedade
urlestá vazia - Adicionando uma propriedade
linka cada entrada de usuário (composta usando o nome e a URL do usuário)
query {
# Retrieve data from the external API
usersWithLinkAndDefaultURL: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url"
}
)
# Set a default URL for users without any
@underEachArrayItem
@underJSONObjectProperty(
by: {
key: "url"
}
)
@default(
value: "https://mysite.com"
condition: IS_EMPTY
)
# Add a new "link" entry on the JSON object
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
passValueOnwardsAs: "userListItem"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "url"
}
},
passOnwardsAs: "userURL"
)
@applyField(
name: "_sprintf",
arguments: {
string: "<a href=\"%s\">%s</a>",
values: [$userURL, $userName]
},
passOnwardsAs: "userLink"
)
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)
}A resposta é:
{
"data": {
"usersWithLinkAndDefaultURL": [
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com",
"link": "<a href=\"https://leoloso.com\">leo</a>"
},
{
"id": 7,
"name": "Test",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Test</a>"
},
{
"id": 2,
"name": "Theme Demos",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Theme Demos</a>"
}
]
}
}As diretivas componíveis podem aninhar uma ou mais diretivas dentro delas. Quando se aninha mais de uma, indicamos isso via o argumento affectDirectivesUnderPos, que contém as posições relativas dessa diretiva até suas diretivas aninhadas.
Na query GraphQL acima, a diretiva @underEachArrayItem (fornecida pela extensão Iteração e Manipulação de Valor de Campo) é uma diretiva componível. Na sua primeira ocorrência, ela aninha apenas uma diretiva, e o argumento affectDirectivesUnderPos pode ser omitido:
@underEachArrayItem
@underJSONObjectProperty(
# ...
)(A propósito, observe que @underJSONObjectProperty também é uma diretiva componível, aninhando a diretiva @default).
Na sua segunda ocorrência, ela aninha as 4 diretivas à sua direita, conforme indicado pelo argumento affectDirectivesUnderPos com valor [1, 2, 3, 4]:
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_sprintf",
# ...
)
@applyField(
name: "_objectAddEntry",
# ...
)🔥 Dicas:
A diretiva @applyField (fornecida pela extensão Campo em Campo) tem dois destinos potenciais para sua saída:
- Fornecer o argumento
passOnwardsAs: "someVariableName"atribuirá o novo valor à variável dinâmica$someVariableName, da qual poderá ser lida pelas próximas diretivas aninhadas:
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)- Fornecer o argumento
setResultInResponse: trueatribuirá o novo valor novamente ao campo (modificando assim a resposta):
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)Extraindo uma propriedade específica dos objetos JSON
O endpoint da API REST newapi.getpop.org/wp-json/newsletter/v1/subscriptions produz uma coleção de dados de assinatura de e-mail, incluindo o e-mail e o idioma do assinante:
[
{
"email": "abracadabra@ganga.com",
"lang": "de"
},
{
"email": "longon@caramanon.com",
"lang": "es"
},
{
"email": "rancotanto@parabara.com",
"lang": "en"
},
{
"email": "quezarapadon@quebrulacha.net",
"lang": "fr"
},
{
"email": "test@test.com",
"lang": "de"
},
{
"email": "emilanga@pedrola.com",
"lang": "fr"
}
]Esta query GraphQL exibe apenas os e-mails da resposta da API, extraindo a propriedade email de cada entrada e substituindo o valor do campo por ela:
query {
emails: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
)
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
}A resposta é:
{
"data": {
"emails": [
"abracadabra@ganga.com",
"longon@caramanon.com",
"rancotanto@parabara.com",
"quezarapadon@quebrulacha.net",
"test@test.com",
"emilanga@pedrola.com"
]
}
}Modificando condicionalmente valores de campos
Este exemplo dá continuidade ao anterior, além de converter o formato dos e-mails na resposta.
A query GraphQL abaixo extrai os e-mails da resposta da API e converte para maiúsculas aqueles dos usuários cujo idioma é inglês ou alemão, via a diretiva componível @if (fornecida pela extensão Manipulação Condicional de Campo):
query {
# Retrieve data from a REST API endpoint
userEntries: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@remove
emails: _echo(value: $__userEntries)
# Iterate all the entries, passing every entry
# (under the dynamic variable $userEntry)
# to each of the next 4 directives
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
affectDirectivesUnderPos: [1, 2, 3, 4]
)
# Extract property "lang" from the entry
# via the functionality field `_objectProperty`,
# and pass it onwards as dynamic variable $userLang
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "lang"
}
}
passOnwardsAs: "userLang"
)
# Execute functionality field `_inArray` to find out
# if $userLang is either "en" or "de", and place the
# result under dynamic variable $isSpecialLang
@applyField(
name: "_inArray"
arguments: {
value: $userLang,
array: ["en", "de"]
}
passOnwardsAs: "isSpecialLang"
)
# Extract property "email" from the entry
# and set it back as the value for that entry
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
# If $isSpecialLang is `true` then execute
# directive `@strUpperCase`
@if(condition: $isSpecialLang)
@strUpperCase
}A resposta é:
{
"data": {
"emails": [
"ABRACADABRA@GANGA.COM",
"longon@caramanon.com",
"RANCOTANTO@PARABARA.COM",
"quezarapadon@quebrulacha.net",
"TEST@TEST.COM",
"emilanga@pedrola.com"
]
}
}A execução de lógica condicional no Gato GraphQL pode ser tornada dinâmica: ao passar uma variável dinâmica para @if(condition:) (e também para @unless(condition:)) que foi avaliada no objeto consultado, a lógica será executada ou não dependendo das condições dessa entidade.
Dessa forma, podemos modificar dinamicamente a resposta para algumas entidades (e não para outras), com base em condições como:
- O post tem comentários?
- O comentário tem respostas?
- O usuário é um administrador?
- A tag/categoria está aplicada a algum post?
- Etc.