appsync subscription with arguments - amazon-web-services

We are having huge troubles with subscriptions with arguments
to simplify the problem Here are the steps to reproduce
create a simpleSchema
type Mutation {
testSubMutation(param: String!): String
}
type Query {
testQuery: String
}
type Subscription {
testSubs(param: String): String
#aws_subscribe(mutations: ["testSubMutation"])
}
I attached a local resolver to the mutation which returns the timestamp.
in one window open the app sync query tab and make the subscription
subscription sub{
testSubs
}
in the other window make a mutation
mutation mut{
testSubMutation(param:"123")
}
works like a charm
now change the subscription to listen to a parameter
subscription sub{
testSubs(param:"123")
}
Does not work any more. :(
Any help is appreciated.

Subscriptions require the parameter you're filtering on to be in the response of the mutation. Could you try updating your mutation to this?
mutation mut{
testSubMutation(param:"123") {
param
}
}

I'm doing same as above for subscription but not getting response, It's only working with one argument room
mutation addMessage {
addMessage(input: {
room: "45a87f5b-ef9e-41cd-9cd7-f3e2f4946d31",
receiver: "3cea9c02-1cf5-4248-8ebe-3580a7a47b8b" }) {
id
room
receiver {
id
userName
}
}
}
subscription roomMessage {
roomMessage(room: "45a87f5b-ef9e-41cd-9cd7-f3e2f4946d31",
receiver: "3cea9c02-1cf5-4248-8ebe-3580a7a47b8b") {
id
room
receiver {
id
userName
}
}
}

Related

AWS AppSync Subscription Arguments Not Working

I'm going crazy over subscriptions with AWS AppSync. My problem is that I can't figure out how to get a filtered subscription. When I pass any arguments into the subscriber, I get nothing in return.
What am I missing?
In schema.graphql my mutation looks like this
testMutation(
id: String!,
val: String!
): TestItem!
My "catch all" subscriber looks like this
subscribeToAllTestMutations: TestItem!
#aws_subscribe(mutations: ["testMutation"])
The problematic subscriber looks like this:
subscribeToTestMutation(id: String!): TestItem!
#aws_subscribe(mutations: ["testMutation"])
When I run this mutation:
mutation {
testMutation(
id: "123-test",
val:"Hey man"
) {
id
val
}
}
I get this response:
{
"data": {
"testMutation": {
"id": "123-test",
"val": "Hey man",
"__typename": "TestItem"
}
}
}
I get the same when I run this:
subscription {
subscribeToAllTestMutations {
id
val
}
}
But when I pass the ID I get nothing, which turns me crazy:
subscription {
subscribeToTestMutation(
id: "123-test"
) {
id
val
}
}
I figured it might have something to do with my mapping templates, but i cannot figure out how to solve it.
I currently, for test purposes, just pass the data through like this with my request mapping template:
{
"version": "2017-02-28",
"payload": $utils.toJson($context.arguments)
}
And, as for resolver mapping template, I just do this:
$utils.toJson($context.result)
Please, if anyone can help me you will save my sanity 🤪

Calling AWS AppSync graphql API from Lambda

I am trying to update the value of a table using the AWS-app sync graphql API,
I am able to create data and add it in a table using graphql mutation in lambda
but when I am trying to update the data its not working.
I am calling this lambda service from an API Gateway.
I am referring this article to code
https://cloudonaut.io/calling-appsync-graphql-from-lambda/
I would like to mentioned git no error in cloud watch log
Here is the schema for my graphql
type Mutation {
createLib_content(input: CreateLib_contentInput!): lib_content
#aws_iam
updateLib_content(input: UpdateLib_contentInput!): lib_content
#aws_iam
deleteLib_content(input: DeleteLib_contentInput!): lib_content
}
input CreateLib_contentInput {
content: String
userId: String
}
input UpdateLib_contentInput {
content: String
id: ID!
}
Create Mutation
graphqlData = await clientDetails.mutate({
mutation: gql(`
mutation CreateLibContent($input: CreateLib_contentInput!) {
createLib_content(input: $input) {
id
content
}
}`),
variables: {
input: {
content : {},
userId : identitiesDetails.userId
}
},
});
Update Mutation
const mutation = gql(`
mutation UpdateLibContent($input: UpdateLib_contentInput!) {
updateLib_content(input: $input) {
userId
content
}
}`);
await clientDetails.mutate({
mutation,
variables: {
input: {
id : "2947c37e-6f76-40d8-8c10-4cd6190d3597",
content : JSON.stringify(event)
}
}
}).promise;
Thanks to #cppgnlearner your guess were right.
I just removed the .promise from my update code
And it started working.
can't believe such a small thing took my whole day.

Does `appsync` support `withFilter` in subscription?

I have a graphql written in nodejs with Apollo Server. Below is the subscription code. As you can see that it uses withFilter which takes two function parameters.
In the first function, it takes the arguments and call pubSub.subscribe('TRANSACTION_REQUEST' + args.transactionId) to subscribe to a topic. Note that the topic name is a dynamic one which includes the transaction ID from the user request.
In the second function, it filter out unmatched userId.
So my question is how can I implement these two functions in Appsync.
const resolvers = {
...
Subscription: {
requestTransaction: {
subscribe: withFilter(
(rootValue: any, args: any, context: any, info: any) => {
console.log('req txn with filter args', args);
return pubSub.subscribe('TRANSACTION_REQUEST' + args.transactionId)(
rootValue,
args,
context,
info,
);
},
(transactionResponse: any, transactionRequest: any) => {
console.log('with filter transaction');
console.log('subscribe:', transactionResponse, transactionRequest);
return (
transactionResponse.userId ===
transactionRequest.transactionInput.userId
);
},
),
},
},
...
In AppSync you won't be able to log as you incrementally filter the subscription events, but you can have the user supply the attributes to filter by so that the resulting subscription events are the same.
Here Event is just the type of the object that your mutation returns:
type Subscription {
subscribeTransaction(topic: String userId: String): Event
#aws_subscribe(mutations: ["fooMutation"])
}
to start a subscription:
subscription onTransact {
subscribeTransaction(topic: "TRANSACTION_REQUEST" + args.transactionId userId: args.userId){
id
foo
bar
}
}
Note:
the name onTransact is arbitrary
assumes transactionId and userId were passed inside args
id, foo and bar will only be returned if the mutation also requested these attributes

AWS appsync query resolver

Currently I have my resolver as a lambda function :
import boto3
from boto3.dynamodb.conditions import Key
def lambda_handler(event, context):
list = []
for device in event['source']['devices'] :
dynamodb = boto3.resource('dynamodb')
readings = dynamodb.Table('readings')
response = readings.query(
KeyConditionExpression=Key('device').eq(device['device'])
)
items = response['Items']
list.extend(items)
return list
I would like to be able to have this as a VTL resolver on the dynamodb. My problem is that my table has a sort key
This means I can't use a batch resolver to query on a bunch of id's because I would also need to provide the sort key, and I just want all the results by primary partition key.
How do you query with a bunch of ids using VTL, basically replicating my lambda function in VTL. Is this even possible ?
Schema added, please excuse the mess it is a work in progress and am attempting many things. Still very new to graphQL
type Device {
id: String
device: String!
}
input DeviceInput {
id: String
device: String!
}
type DeviceReadings {
devices: [Device]
}
type Mutation {
createDevice(input: DeviceInput): Device
}
type PaginatedDevices {
devices: [Device]
readings: [Reading]
cows: [cow]
nextToken: String
}
type Query {
getAllUserDevices(nextToken: String, count: Int): PaginatedDevices
getAllDeviceReadings: DeviceReadings
getAllUserReadings: DeviceReadings
getAllReadings(deviceId: String!): Readings
getCowReadings(cowId: String!): UserCowReadings
}
type Reading {
device: String
time: Int
cow: Int
battery: String
}
type Readings {
items: [Reading]
}
type UserCowReadings {
devices: [Device]
readings: [Reading]
}
type cow {
id: Int
device: String
nait: String
}
schema {
query: Query
mutation: Mutation
}
Yes you can do this but you will need to tweak your schema a bit. In that lambda you are essentially saying "for each device do a DynamoDB query to get the most recent readings for that device". Conceptually I would say that devices have many readings. With this in mind, lets make a schema:
type Device {
id: ID!
name: String
# Get the most recent readings for this device.
# Do a Query where "device = $ctx.source.id"
readings(limit: Int, nextToken: String): ReadingConnection
}
type Reading {
# Use the source's device id in the table to fetch the real device
# GetItem where device = $ctx.source.device (and any sort key condition)
device: Device
time: Int
cow: Int
battery: String
}
type ReadingConnection {
items: [Reading]
nextToken: String
}
type DeviceConnection {
items: [Device]
nextToken: String
}
type Query {
getAllDevices(limit: Int, nextToken: String): DeviceConnection
}
You may then paginate through your devices and paginate through each devices readings separately:
query GetAllDevicesAndReadings {
getAllDevices(first: 10) {
items {
id
name
readings(limit: 10) {
time
cow
battery
}
}
}
}
I recommend using the drop down in the AppSync console's resolver page to get more ideas for what you can do with the resolver VTL to implement these GetItems and Queries. This is a good starting point. Let me know if you have trouble implementing the VTL.

AWS AppSync - Directive "aws_subscribe" may not be used on FIELD_DEFINITION

I'm trying to get to grips with AWS AppSync. I'm quite new to GraphQL. I've got the following GraphQL:
type Mutation {
deleteParcel(geoHash: String!, type_id: String!): Parcel
addParcel(input: ParcelInput!): Parcel
batchAddParcels(parcels: [ParcelInput]): [Parcel]
}
type Parcel {
geoHash: String!
type_id: String!
}
type ParcelConnection {
items: [Parcel]
}
input ParcelInput {
geoHash: String!
type_id: String!
}
input ParcelsInput {
parcels: [ParcelInput]
}
type Query {
getNearbyParcels(geoHash: String!): ParcelConnection
}
type Subscription {
onAddParcel(geoHash: String, type_id: String): Parcel
#aws_subscribe(mutations: ["addParcel"])
onBatchAddParcels(geoHash: String): Parcel
#aws_subscribe(mutations: ["batchAddParcels"])
onDeleteParcel(geoHash: String, type_id: String): Parcel
#aws_subscribe(mutations: ["deleteParcel"])
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
All seems to be setup fine on AWS console. I get the schema.json and then run command:
aws-appsync-codegen generate AWSGraphQL.graphql --schema schema.json --output AppsyncAPI.swift
and get the response:
../SnatchHQ/snatch_appsync/AppSync/AWSGraphQL.graphql: Directive "aws_subscribe" may not be used on FIELD_DEFINITION.
.../SnatchHQ/snatch_appsync/AppSync/AWSGraphQL.graphql: Directive "aws_subscribe" may not be used on FIELD_DEFINITION.
.../SnatchHQ/snatch_appsync/AppSync/AWSGraphQL.graphql: Directive "aws_subscribe" may not be used on FIELD_DEFINITION.
error: Validation of GraphQL query document failed
Can anyone help?
If the file AWSGraphQL.graphql is your API GraphQL schema, then that explains the problem. What you need to do is define a *.graphql file that defines your query, mutation, and subscription operations based on your GraphQL API. For example, the following query definitions would match your schema
mutation AddParcel($geoHash: String!, $type_id: String!) {
addParcel(input: {
geoHash: $geoHash
type_id: $typeId
}) {
...Parcel
}
}
query GetNearbyParcels($geoHash: String!) {
getNearbyParcels(
geoHash: $geoHash
) {
...ParcelConnection
}
}
subscription OnAddParcel {
onAddParcel {
...Parcel
}
}
fragment Parcel on Parcel {
geoHash
type_id
}
fragment ParcelConnection on Parcel Connection {
items {
...Parcel
}
}
Assuming you named it something like parcels.graphql, you can then call the following to generate a Swift implementation of the AddParcel mutation, the GetNearbyParcels query, and the OnAddParcel subscription
aws-appsync-codegen generate parcels.graphql \
--schema schema.json \
--output AppSyncParcelsAPI.swift