Tutoriel du schéma
Tutoriel du schémaLeçon 25 : Transformation de données depuis une API externe

Leçon 25 : Transformation de données depuis une API externe

Cette leçon du tutoriel démontre des exemples d'adaptation de la réponse d'une API externe selon nos besoins.

Ajout de valeurs par défaut et de propriétés supplémentaires à chaque entrée

L'endpoint de l'API REST newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url produit des données d'utilisateur, avec certains utilisateurs ayant la propriété url vide :

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

La requête GraphQL ci-dessous transforme cette réponse :

  • En ajoutant une URL par défaut aux utilisateurs dont la propriété url est vide
  • En ajoutant une propriété link à chaque entrée d'utilisateur (composée à partir du nom et de l'URL de l'utilisateur)
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
      )
}

La réponse est :

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

Les directives composables peuvent imbriquer une ou plusieurs directives en leur sein. Lorsqu'on en imbrique plusieurs, on l'indique via l'argument affectDirectivesUnderPos, qui contient les positions relatives de cette directive vers ses directives imbriquées.

Dans la requête GraphQL ci-dessus, la directive @underEachArrayItem (fournie par l'extension Itération et Manipulation de Valeur de Champ) est une directive composable. À sa première occurrence, elle n'imbrique qu'une seule directive, et l'argument affectDirectivesUnderPos peut être omis :

    @underEachArrayItem
      @underJSONObjectProperty(
        # ...
      )

(Par ailleurs, notez que @underJSONObjectProperty est également une directive composable, imbriquant la directive @default).

À sa deuxième occurrence, elle imbrique les 4 directives à sa droite, comme indiqué par l'argument affectDirectivesUnderPos avec la valeur [1, 2, 3, 4] :

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



🔥 Conseils :

La directive @applyField (fournie par l'extension Champ sur Champ) a deux destinations potentielles pour sa sortie :

  • Fournir l'argument passOnwardsAs: "someVariableName" assignera la nouvelle valeur à la variable dynamique $someVariableName, depuis laquelle elle peut être lue par les directives imbriquées suivantes :
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $userListItem,
          by: {
            key: "name"
          }
        },
        passOnwardsAs: "userName"
      )
  • Fournir l'argument setResultInResponse: true assignera la nouvelle valeur de nouveau au champ (et modifiera donc la réponse) :
      @applyField(
        name: "_objectAddEntry",
        arguments: {
          object: $userListItem,
          key: "link",
          value: $userLink
        },
        setResultInResponse: true
      )

Extraction d'une propriété spécifique depuis les objets JSON

L'endpoint de l'API REST newapi.getpop.org/wp-json/newsletter/v1/subscriptions produit une collection de données d'abonnement par email, incluant l'email et la langue de l'abonné :

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

Cette requête GraphQL n'affiche que les emails de la réponse de l'API, en extrayant la propriété email de chaque entrée et en remplaçant la valeur du champ par celle-ci :

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

La réponse est :

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

Modification conditionnelle des valeurs de champ

Cet exemple s'appuie sur le précédent, en convertissant également le format des emails dans la réponse.

La requête GraphQL ci-dessous extrait les emails de la réponse de l'API, et convertit en majuscules ceux des utilisateurs dont la langue est l'anglais ou l'allemand via la directive composable @if (fournie par l'extension Manipulation Conditionnelle de Champ) :

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
}

La réponse est :

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

L'exécution de logique conditionnelle dans Gato GraphQL peut être rendue dynamique : En passant une variable dynamique à @if(condition:) (ainsi qu'à @unless(condition:)) qui a été évaluée sur l'objet interrogé, la logique s'exécutera ou non selon les conditions de cette entité.

De cette façon, nous pouvons modifier dynamiquement la réponse pour certaines entités (et pas d'autres), selon des conditions telles que :

  • L'article a-t-il des commentaires ?
  • Le commentaire a-t-il des réponses ?
  • L'utilisateur est-il un administrateur ?
  • Le tag/la catégorie est-il appliqué à un article ?
  • Etc.