Données en temps réel - AWS AppSync

Données en temps réel

Directives d'abonnement de schéma GraphQL

Les abonnements dans AWS AppSync sont appelés en tant que réponse à une mutation. Cela signifie que vous pouvez transformer n'importe quelle source de données dans AWS AppSync en source de données en temps réel, en spécifiant une directive de schéma GraphQL lors d'une mutation. Le kit SDK AWS AppSync client gère automatiquement la gestion des connexions par abonnement. Le kit SDK utilise soit des WebSockets purs, soit MQTT sur WebSockets comme protocole réseau entre le client et le service. Le protocole dépend de la version du client que vous utilisez.

Remarque : Pour contrôler les autorisations au moment de la connexion à un abonnement, vous pouvez exploiter des contrôles comme IAM, des groupes d'identités Amazon Cognito ou des groupes d'utilisateurs Amazon Cognito pour les autorisations au niveau des champs. Pour le contrôle précis des accès sur les abonnements, vous pouvez attacher des résolveurs à vos champs d'abonnement et appliquer une logique en utilisant l'identité de l'appelant et les sources de données AWS AppSync. Pour en savoir plus, consultez la section Sécurité.

Les abonnements sont déclenchés à partir des mutations et le jeu de sélection de mutations est envoyé aux abonnés.

L'exemple suivant montre comment utiliser les abonnements GraphQL. Il ne spécifie pas de source de données, car la source de données pourrait être AWS Lambda, Amazon DynamoDB ou Amazon Elasticsearch Service.

Pour commencer avec les abonnements, vous devez ajouter un point d'entrée d'abonnement à votre schéma :

schema { query: Query mutation: Mutation subscription: Subscription }

Supposons que vous disposez d'un site de blog et que vous souhaitez vous abonner à de nouveaux blogs et à des modifications de blogs existants. Pour ce faire, vous devez ajouter la définition Subscription suivante à votre schéma :

type Subscription { addedPost: Post updatedPost: Post deletedPost: Post }

Supposons encore que vous disposez des mutations suivantes :

type Mutation { addPost(id: ID! author: String! title: String content: String url: String): Post! updatePost(id: ID! author: String! title: String content: String url: String ups: Int! downs: Int! expectedVersion: Int!): Post! deletePost(id: ID!): Post! }

Vous pouvez transformer ces champs en temps réel en ajoutant une directive @aws_subscribe(mutations: ["mutation_field_1", "mutation_field_2"]) pour chacun des abonnements pour lesquels vous souhaitez recevoir des notifications, comme suit :

type Subscription { addedPost: Post @aws_subscribe(mutations: ["addPost"]) updatedPost: Post @aws_subscribe(mutations: ["updatePost"]) deletedPost: Post @aws_subscribe(mutations: ["deletePost"]) }

Comme @aws_subscribe(mutations: ["",..,""]) accepte un tableau d'entrées de mutation, vous pouvez spécifier plusieurs mutations, qui déclenchent un abonnement. Si vous vous abonnez à partir d'un client, votre requête GraphQL peut ressembler à ce qui suit :

subscription NewPostSub { addedPost { __typename version title content author url } }

La requête d'abonnement ci-dessus est nécessaire pour les outils et les connexions client. Cependant, si vous utilisez MQTT sur WebSockets, le client déclenchant la mutation spécifie le jeu de sélection que les abonnés reçoivent. Pour le démontrer, supposons qu'une mutation ait été faite à partir d'un autre client mobile ou d'un serveur (par exemple, mutation addPost(...){id author title }). Dans ce cas, le contenu, la version et l'URL ne sont pas publiés aux abonnés. L'ID, l'auteur et le titre sont publiés à la place.

Si vous utilisez le client WebSockets pur, le filtrage des jeux de sélection est effectué par client, car chaque client peut définir son propre jeu de sélection. Dans ce cas, le jeu de sélection d'abonnement doit être un sous-ensemble du jeu de sélection de mutation. Par exemple, un abonnement addedPost{author title} lié à la mutation addPost(...){id author title url version} reçoit uniquement l'auteur et le titre de la publication. Il ne reçoit pas les autres champs. Cependant, si la mutation n'avait pas l'auteur dans son ensemble de sélection, l'abonné obtiendrait une valeur null pour le champ auteur (ou une erreur dans le cas où le champ auteur est défini comme « required/not-null » dans le schéma).

De plus, si vous utilisez MQTT sur WebSockets dans votre application, il y a quelques changements dont vous devez être conscient. Si vous n'avez pas configuré le jeu de sélection d'abonnement associé avec les champs requis et que vous vous êtes fié aux champs de mutation pour envoyer les données au client abonné, le comportement change lorsque vous passez à des WebSockets purs. Dans l'exemple ci-dessus, un abonnement sans le champ « auteur » défini dans son jeu de sélection retourne toujours le nom de l'auteur avec MQTT sur WebSockets, car le champ est défini dans la mutation ; le même comportement ne s'applique pas aux WebSockets purs. Le jeu de sélection d'abonnement est essentiel lors de l'utilisation de WebSockets purs : si un champ n'est pas explicitement défini dans l'abonnement, il n'est pas retourné par AWS AppSync.

Dans l'exemple précédent, les abonnements n'avaient pas d'arguments. Imaginez que votre schéma se présente comme suit :

type Subscription { updatedPost(id:ID! author:String): Post @aws_subscribe(mutations: ["updatePost"]) }

Dans ce cas, votre client définit un abonnement ainsi :

subscription UpdatedPostSub { updatedPost(id:"XYZ", author:"ABC") { title content } }

Le type de retour d'un champ subscription dans votre schéma doit correspondre au type de retour du champ de mutation correspondant. L'exemple précédent illustrait cela avec addPost et addedPost qui ont été renvoyés en tant que type de Post.

Pour configurer des abonnements sur le client, consultez Création d'une application cliente.

Utilisation d'arguments d'abonnement

Une part importante de l'utilisation des abonnements GraphQL consiste à comprendre quand et comment utiliser les arguments, car des changements subtils vous permettent de modifier quand et comment les clients sont avertis des mutations qui interviennent. Pour cela, reportez-vous à l'exemple de schéma figurant dans la section de démarrage rapide Lancement d'un exemple de schéma, qui crée des « Événements » et des « Commentaires ». Pour cet exemple de schéma, la mutation suivante survient :

type Mutation { createEvent( name: String!, when: String!, where: String!, description: String! ): Event deleteEvent(id: ID!): Event commentOnEvent(eventId: ID!, content: String!, createdAt: String!): Comment }

Dans l'exemple par défaut, les clients peuvent s'abonner aux Commentaires lorsqu'un argument eventId spécifique est transmis :

type Subscription { subscribeToEventComments(eventId: String!): Comment @aws_subscribe(mutations: ["commentOnEvent"]) }

Toutefois, si vous voulez permettre aux clients de s'abonner à un événement unique OU à tous les événements, vous pouvez rendre cet argument facultatif en supprimant le point d'exclamation (!) dans le prototype d'abonnement :

subscribeToEventComments(eventId: String): Comment

Grâce à cette modification, les clients qui ont omis cet argument peuvent obtenir des commentaires pour tous les événements. De plus, si vous voulez que les clients s'abonnent explicitement à tous les commentaires pour tous les événements, vous devez supprimer l'argument :

subscribeToEventComments: Comment

Utilisez ceux-ci est pour des commentaires sur un ou plusieurs événements. Si vous voulez tout savoir concernant tous les événements qui sont créés, vous pouvez effectuer les opérations suivantes :

type Subscription { subscribeToNewEvents: Event @aws_subscribe(mutations: ["createEvent"]) }

Plusieurs arguments peuvent également être transmis. Par exemple, si vous voulez être averti des nouveaux événements à un endroit et un moment spécifiques, procédez comme suit :

type Subscription { subscribePlaceDate(where: String! when: String!): Event @aws_subscribe(mutations: ["createEvent"]) }

Ainsi, l'application cliente peut maintenant faire ce qui suit :

subscription myplaces { subscribePlaceDate(where: "Seattle" when: "Saturday"){ id name description } }

La valeur null de l'argument a une signification

Lorsque vous effectuez une requête d'abonnement dans AWS AppSync, une valeur d'argument null filtre les résultats différemment de l'omission complète de l'argument.

Expliquons cela avec un exemple. Revenons à l'exemple d'application d'événements où nous pouvons créer des événements et publier des commentaires sur les événements. Consultez l'exemple de schéma de la section de démarrage rapide Lancement d'un exemple de schéma.

Modifions notre schéma pour inclure un nouveau champ location sur le champ Comment, qui décrit d'où le commentaire a été envoyé. La valeur peut être un ensemble de coordonnées ou un lieu. Regardez le schéma ci-dessous, notez que nous l'avons réduit par souci de concision :

type Comment { # The id of the comment's parent event. eventId: ID! # A unique identifier for the comment. commentId: String! # The comment's content. content: String # Location where the comment was made location: String } type Event { id: ID! name: String where: String when: String description: String } type Mutation { commentOnEvent(eventId: ID!, location: String, content: String): Comment } type Subscription { subscribeToEventComments(eventId: String!, location: String, content: String): Comment @aws_subscribe(mutations: ["commentOnEvent"]) }

Vous pouvez remarquer le nouveau champ facultatif Comment.location.

Supposons maintenant que nous voulons être informés de tous les commentaires lorsqu'ils sont publiés pour un événement particulier. Nous écririons alors l'abonnement suivant :

subscribeToEventComments(eventId: "1") { eventId commentId location content }

Maintenant, si nous ajoutons plutôt l'argument de champ location: null à l'abonnement ci-dessus,

subscribeToEventComments(eventId: "1" location: null) { eventId commentId location content }

nous posons une autre question. Cet abonnement enregistre désormais le client pour être informé de tous les commentaires qui n'ont pas fourni de lieu pour un événement particulier.