awslabs / aws-mobile-appsync-sdk-js

JavaScript library files for Offline, Sync, Sigv4. includes support for React Native
Apache License 2.0
920 stars 266 forks source link

Need Example of calling mutation from NodeJS/Lambda #202

Closed OlivierPT closed 5 years ago

OlivierPT commented 6 years ago

Hi,

I need to call a mutation from an AWS Lambda and I don't manage to make it work. Unfortunately, I don't find any example of directly using AppSync client for calling a mutation...

Currently, my code looks like that: const AddNotificationMutation = gql(mutation addNotification($notificationId: ID!, $recipientId: String!, $dateTime: String!, $content: String) { addNotification(notificationId: $notificationId, recipientId: $recipientId, dateTime: $dateTime, content: $content) { notificationId recipientId content dateTime } });

const AppSyncConfig = { url: process.env.GRAPHQL_API_URL, region: process.env.REGION, auth: { type: AUTH_TYPE.AWS_IAM, }, disableOffline: true, };

// Set up Apollo client

`const client = new AWSAppSyncClient(AppSyncConfig);

export const createNotification = (notification, callback) => {

logger.debug('Call for notification: %s', JSON.stringify(notification));
client.hydrated().then(client => {
    client.mutate({ mutation: AddNotificationMutation, variables: notification, fetchPolicy: 'network-only'})
        .then(newNotification => {
            logger.debug("newNotification created: %s", JSON.stringify(newNotification));
            return callback(null, newNotification);
        })
        .catch(error => {
            logger.error("newNotification failed: %s", JSON.stringify(error));
            return callback(error, notification);
        });
    });

}`

undefobj commented 6 years ago

You will need to set fetchPolicy: 'network-only' Take a look at this example https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-node.html#create-a-client-application which has //Uncomment for AWS Lambda in the code.

OlivierPT commented 6 years ago

Hi,

Actually, I started from this example and if you check my code in the first post, you will see the option fetchPolicy: 'network-only' is well set.

My issue is that the example from AWS is only about sending a query but I need to trigger a mutation. And I can't find anywhere an exemple to do that. So my point would be to have the same example but for a mutation :)

undefobj commented 6 years ago

The difference between a query and a mutation is just the statement in the query variable. So if you had an addPost mutation you could do something like this:

const query = gql(`
mutation AddPost {
addPost(name:'xxxx') {
    name
}
}`);
OlivierPT commented 6 years ago

Hi Richard,

I am sorry, maybe this question is an something obvious. Actually, I am not talking about the mutation declaration but of the usage of the AppSync client, in Javascript to run the mutation...

So, do you mean that I should use client.query({ query: AddNotificationMutation, fetchPolicy: 'network-only' }) to invoke my mutation? Or is there another function to be used instead?

Thanks,

OlivierPT commented 6 years ago

Hi,

I am still looking for an example of calling a mutation from a NodeJS Lambda. I tried several solution without any success.

Currently, my code is:

Mutation déclaration: const AddNotificationMutation = gql(mutation addNotification($notificationId: ID!, $recipientId: String!, $dateTime: String!, $content: String) { addNotification(notificationId: $notificationId, recipientId: $recipientId, dateTime: $dateTime, content: $content) { notificationId recipientId content dateTime } });

Call to the mutation: client.hydrated().then(client => { client.mutate({ mutation: AddNotificationMutation, variables: notification, fetchPolicy: 'network-only'}) .then(newNotification => { logger.debug("newNotification created: %s", JSON.stringify(newNotification)); return callback(null, newNotification); }) .catch(error => { logger.error("newNotification failed: %s", JSON.stringify(error)); return callback(error, notification); }); }); }

Can someone help to find what is wrong there and what code I should use?

AlpacaGoesCrazy commented 6 years ago

If your mutation invokes data source located on the same aws account, why not invoke this data source directly from your lambda without AppSync api?

OlivierPT commented 6 years ago

Yes, it would be more simple to do so... But I want that this mutation trigger update for a Subscription done on the client side. It is this only way I found to trigger a Subscription based on action done on the backend...

Would you see another solution?

damonmaria commented 6 years ago

@OlivierPT I was having the same trouble as you. Solved it by importing AWS and then setting credentials from the config from that:

import AWS from 'aws-sdk/global'
import { AUTH_TYPE } from 'aws-appsync/lib/link/auth-link'

new AWSAppSyncClient(
    {
      url: env.graphQlApiEndpoint,
      region: AWS.config.region,
      auth: {
        type: AUTH_TYPE.AWS_IAM,
        credentials: AWS.config.credentials,
      },
      disableOffline: true,
    },
    {
      defaultOptions: {
        query: {
          fetchPolicy: 'network-only',
          errorPolicy: 'all',
        },
      },
    },
  )
damonmaria commented 6 years ago

@undefobj The docs you linked to (https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-node.html#create-a-client-application) are out of date as you no longer need to do all the shinanigans with global. Just import isomorphic-fetch. They should really be updated.

harleyguru commented 6 years ago

Hi @OlivierPT

const mutation = gql(`
    mutation($infoID: String!){
            deleteInfo(infoID: $infoID) {
              infoID
              noOfDays
              noOfItems
              infoName
             }
    }`);

  const client = new AWSAppSyncClient({
    url: url,
    region: region,
    auth: {
        type: type,
        credentials: credentials,
    }
  });

  client.hydrated().then(function (client) {
      //Now run a query
      client.mutate({ mutation: mutation, variables:{infoID: infoID} })
          .then(function logData(data) {
              console.log('results of mutate: ', data);
          })
          .catch(console.error);
  });

This will be helpful for you?

OlivierPT commented 6 years ago

Hi,

I was still struggling with this and the answer from @damonmaria solved my issue. It seems that it was only a client setup issue. I was already on the same code base that what provided by @harleyguru so I was on the good path :)

Indeed, I that would be very helpful that the documentation gets updated and completed with the mutation case!

Thank you guys

harleyguru commented 6 years ago

Hi @OlivierPT Have you ever faced the situation you need to subscribe to mutations for multiple objects? For example, I need to subscribe to the events that multiple objects are updated regarding the specified id list of those.

Thanks

OlivierPT commented 6 years ago

Hi @harleyguru,

Actually, I am quiet beginner in GraphQL so didn't have to do that yet (If I understand right your need)... If you want to update multiple objects at the same time, maybe you can use the "batch" operations (https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-batch.html)? (I didn't use it...)

So then, you can subscribe to this mutation?

harleyguru commented 6 years ago

Hi @OlivierPT Thanks for your update 👍 Yeah, but it's grouping operation of multiple mutations against DynamoDB. So I think we can't define that mutation itself and subscribe to it because it will work by defining in only resolver template for DDB. But I will give it a try for your suggestion. Thanks

clearblood commented 6 years ago

I tried to run your code @harleyguru and i get this error error Any ideas on what could be going on?

harleyguru commented 6 years ago

hi @clearblood , sorry to hear. This code should work perfectly. did you follow the documentation from AWS AppSync? https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-node.html#create-a-client-application

clearblood commented 6 years ago

@harleyguru Turns out it was a problem with my version of Apollo client. I updated it to the latest and it worked. Thanks so much for the prompt reply though!

xenowits commented 3 years ago

It actually works. I am using this client in lambda. I had to replace fetchPolicy to 'no-cache'. Thanks people!