Schema-tutorial
Schema-tutorialLes 25: Gegevens transformeren van een externe API

Les 25: Gegevens transformeren van een externe API

Deze tutorialles demonstreert voorbeelden van het aanpassen van de respons van een externe API naar wat je nodig hebt.

Standaardwaarden en extra eigenschappen toevoegen aan elk item

Het REST API-endpoint newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url levert gebruikersgegevens op, waarbij sommige gebruikers een lege eigenschap url hebben:

[
  {
    "id": 1,
    "name": "leo",
    "url": "https://leoloso.com"
  },
  {
    "id": 7,
    "name": "Test",
    "url": ""
  },
  {
    "id": 2,
    "name": "Theme Demos",
    "url": ""
  }
]

De onderstaande GraphQL query transformeert deze respons:

  • Door een standaard-URL toe te voegen aan gebruikers waarvan de eigenschap url leeg is
  • Door een eigenschap link toe te voegen aan elk gebruikersitem (samengesteld uit de naam en URL-waarden van de gebruiker)
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
      )
}

De respons is:

{
  "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>"
      }
    ]
  }
}

Composable directives kunnen één of meer directives in zich nesten. Als je meer dan één nestelt, geef je dit aan via het argument affectDirectivesUnderPos, dat de relatieve posities bevat van die directive tot zijn geneste directives.

In de bovenstaande GraphQL query is directive @underEachArrayItem (geleverd door de Field Value Iteration and Manipulation extensie) een composable directive. Bij het eerste voorkomen nestelt het slechts één directive en kan het argument affectDirectivesUnderPos worden weggelaten:

    @underEachArrayItem
      @underJSONObjectProperty(
        # ...
      )

(Trouwens, merk op dat @underJSONObjectProperty ook een composable directive is, die de @default directive nestelt).

Bij het tweede voorkomen nestelt het de 4 directives rechts ervan, zoals aangegeven door het argument affectDirectivesUnderPos met de waarde [1, 2, 3, 4]:

    @underEachArrayItem(
      affectDirectivesUnderPos: [1, 2, 3, 4],
      # ...
    )
      @applyField(
        name: "_objectProperty",
        # ...
      )
      @applyField(
        name: "_objectProperty",
        # ...
      )
      @applyField(
        name: "_sprintf",
       # ...
      )
      @applyField(
        name: "_objectAddEntry",
        # ...
      )



🔥 Tips:

Directive @applyField (geleverd door de Field on Field extensie) heeft twee mogelijke bestemmingen voor de uitvoer:

  • Het opgeven van het argument passOnwardsAs: "someVariableName" wijst de nieuwe waarde toe aan de dynamische variabele $someVariableName, waaruit de volgende geneste directives die kunnen lezen:
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $userListItem,
          by: {
            key: "name"
          }
        },
        passOnwardsAs: "userName"
      )
  • Het opgeven van het argument setResultInResponse: true wijst de nieuwe waarde opnieuw toe aan het veld (en wijzigt daarmee de respons):
      @applyField(
        name: "_objectAddEntry",
        arguments: {
          object: $userListItem,
          key: "link",
          value: $userLink
        },
        setResultInResponse: true
      )

Een specifieke eigenschap uit de JSON-objecten extraheren

Het REST API-endpoint newapi.getpop.org/wp-json/newsletter/v1/subscriptions levert een verzameling e-mailabonnementgegevens op, inclusief het e-mailadres en de taal van de abonnee:

[
  {
    "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"
  }
]

Deze GraphQL query toont alleen de e-mailadressen uit de API-respons, door de eigenschap email uit elk item te extraheren en de veldwaarde daarmee te vervangen:

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
      )
}

De respons is:

{
  "data": {
    "emails": [
      "abracadabra@ganga.com",
      "longon@caramanon.com",
      "rancotanto@parabara.com",
      "quezarapadon@quebrulacha.net",
      "test@test.com",
      "emilanga@pedrola.com"
    ]
  }
}

Veldwaarden conditioneel aanpassen

Dit voorbeeld bouwt voort op het vorige en converteert bovendien het formaat van de e-mailadressen in de respons.

De onderstaande GraphQL query extraheert de e-mailadressen uit de API-respons en converteert naar hoofdletters die van gebruikers waarvan de taal Engels of Duits is, via de composable directive @if (geleverd door de Conditional Field Manipulation extensie):

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
}

De respons is:

{
  "data": {
    "emails": [
      "ABRACADABRA@GANGA.COM",
      "longon@caramanon.com",
      "RANCOTANTO@PARABARA.COM",
      "quezarapadon@quebrulacha.net",
      "TEST@TEST.COM",
      "emilanga@pedrola.com"
    ]
  }
}

Het uitvoeren van conditionele logica in Gato GraphQL kan dynamisch worden gemaakt: door een dynamische variabele door te geven aan @if(condition:) (en ook aan @unless(condition:)) die is geëvalueerd op het bevraagde object, wordt logica al dan niet uitgevoerd afhankelijk van de condities van die entiteit.

Op deze manier kunnen we de respons dynamisch aanpassen voor sommige entiteiten (en niet voor andere), op basis van condities zoals:

  • Heeft het bericht reacties?
  • Heeft de reactie antwoorden?
  • Is de gebruiker een beheerder?
  • Is de tag/categorie toegepast op een bericht?
  • Etc.