Appsync: Subscribe to element in array - amazon-web-services

With respect to AWS AppSync Is there a way of subscribing to an element in an array , eg:
onSendMessage(recipientIds:[myID,otherPotentiallyRandomAndUnknownIds]) {
}
I have tried simply adding the element I'm looking for, however it doesn't trigger a subscription if I'm missing the other elements (and in order too)

Unfortunately this is something that can't be done trivially. Also the as you noted the order matters because in GraphQL it should viewed as a List (which is ordered). So the subscription triggers expecting the order you provided on the schema. It also expects the exact arguments you provide in the list because a GraphQL Schema is essentially viewed as a contract by clients so if the contract dictates that the subscription is on a List with these elements in this order - then it will initiate the subscription based on that.
Now what you could do is set up a dynamo stream (assuming DynamoDB as your data source) that feeds any changes on the table into a lambda from where you can make a mutation on AppSync (depending on if a change to was made to an element in the array) to trigger a subscription (set up simple mutation/subscriptions for this use case only). This is sort of a hack-y workaround, and there may be other novel solutions you can explore.

Related

Return all items or a single item from DynamoDB from AWS API Gateway endpoint

I am using AWS proxy with AWS API Gateway to interact with a DynamoDB table. I have an API resource, under which I have a GET method with the below configuration:
The API uses the Scan action as seen above to fetch all the items from the DynamoDB table. I also have the following request integration mapping template;
{
"TableName": tableName
}
Its really simple. But my problem is that I would like to add another GET method to get each item by their id, which will be supplied in the URL as a param. However, since I have already setup one GET method, I am not able to setup another to fetch only a single item. I am aware I can use mapping templates and Scan as given in the docs to conditionally fetch items if a param is given, but that would mean scanning the entire table, which is a waste each time I want to fetch a single item.
Is there any other way to do this?

DynamoDB Upsert - Update or Create?

We use DynamoDB UpdateItem.
This acts as an "upsert" as we can learn from the documentation
Edits an existing item's attributes, or adds a new item to the table if it does not already exist. [...]
When we make a request, to determine if an item was created or an existing item was updated, we request ALL_OLD. This works great and allows us to differentiate between update and create.
As an additional requirement we also want to return ALL_NEW, but still know the type of operation that was performed.
Question: Is this possible to do in a single request or do we have to make a second (get) request?
By default this is not supported in DynamoDB, there is no ALL or NEW_AND_OLD_IMAGES as there is in DynamoDB streams, but you can always go DIY.
When you do the UpdateItem call, you have the UpdateExpression, which is basically the list of changes to apply to the item. Given that you told DynamoDB to return the item as it looked like before that operation, you can construct the new state locally.
Just create a copy of the ALL_OLD response and locally apply the changes from the UpdateExpression to it. That's definitely faster than two API calls at the cost of a slightly more complex implementation.

Get all items in DynamoDB with API Gateway's Mapping Template

Is there a simple way to retrieve all items from a DynamoDB table using a mapping template in an API Gateway endpoint? I usually use a lambda to process the data before returning it but this is such a simple task that a Lambda seems like an overkill.
I have a table that contains data with the following format:
roleAttributeName roleHierarchyLevel roleIsActive roleName
"admin" 99 true "Admin"
"director" 90 true "Director"
"areaManager" 80 false "Area Manager"
I'm happy with getting the data, doesn't matter the representation as I can later transform it further down in my code.
I've been looking around but all tutorials explain how to get specific bits of data through queries and params like roles/{roleAttributeName} but I just want to hit roles/ and get all items.
All you need to do is
create a resource (without curly braces since we dont need a particular item)
create a get method
use Scan instead of Query in Action while configuring the integration request.
Configurations as follows :
enter image description here
now try test...you should get the response.
to try it out on postman deploy the api first and then use the provided link into postman followed by your resource name.
API Gateway allows you to Proxy DynamoDB as a service. Here you have an interesting tutorial on how to do it (you can ignore the part related to index to make it work).
To retrieve all the items from a table, you can use Scan as the action in API Gateway. Keep in mind that DynamoDB limits the query sizes to 1MB either for Scan and Query actions.
You can also limit your own query before it is automatically done by using the Limit parameter.
AWS DynamoDB Scan Reference

AWS AppSync Subscription Arguments

What can the arguments on an AppSync GraphQL subscription be used for? According to the real-time data page on the docs:
An important part of using GraphQL subscriptions is understanding when and how to use arguments, as subtle changes will allow you to modify how and when clients are notified of mutations that have occured.
(...)
In the default sample, clients can subscribe to Comments when a specific eventId argument is passed through
I can't find any way to access the subscription arguments, though. I have different 'channels' of comments that I'd like users to be able to subscribe to individually, optionally with a password. The subscription I've set up responds to comments in all channels instead.
Is there any way to 'filter' the data coming through the subscription with a mapping template or similar? If not, what's the intended use of the subscription arguments? Must the filtering be done client side?
The name of the argument is expected to be the same as the name of the field in the mutation response that triggered the event. If your mutation returns a value of type "Post" that contains a field "title" then passing an argument named "title" to the subscription that is subscribed to that mutation will only get pushed values where the "title" passed to the subscription equals the value of field named "title" returned by the mutation.
The arguments control what data clients will get subscription notifications from. For example if you put in an argument via the schema which is required by using the bang (!) symbol then clients can only subscribe to data on a specific mutation for that parameter.
GraphQL arguments, including those passed in a subscription, should be available via $ctx.args in your resolver (this is shorthand for $context.arguments). For example if you have a query of getThing(name:"XYZ") then you can access in your resolver with $ctx.args.name.
For your use case I would suggest using arguments along with a resolver on the subscription so that users can only subscribe to a channel by that argument, if they match some authorization criteria, such as the password or looking at the logged in user. You can find an example of this here: https://docs.aws.amazon.com/appsync/latest/devguide/security-authorization-use-cases.html#real-time-data

Query AWS SNS Endpoints by User Data

Simple question, but I suspect it doesn't have a simple or easy answer. Still, worth asking.
We're creating an implementation for push notifications using AWS with our Web Server running on EC2, sending messages to a queue on SQS, which is dealt with using Lambda, which is sent finally to SNS to be delivered to the iOS/Android apps.
The question I have is this: is there a way to query SNS endpoints based on the custom user data that you can provide on creation? The only way I see to do this so far is to list all the endpoints in a given platform application, and then search through that list for the user data I'm looking for... however, a more direct approach would be far better.
Why I want to do this is simple: if I could attach a User Identifier to these Device Endpoints, and query based on that, I could avoid completely having to save the ARN to our DynamoDB database. It would save a lot of implementation time and complexity.
Let me know what you guys think, even if what you think is that this idea is impractical and stupid, or if searching through all of them is the best way to go about this!
Cheers!
There isn't the ability to have a "where" clause in ListTopics. I see two possibilities:
Create a new SNS topic per user that has some identifiable id in it. So, for example, the ARN would be something like "arn:aws:sns:us-east-1:123456789:know-prefix-user-id". The obvious downside is that you have the potential for a boat load of SNS topics.
Use a service designed for this type of usage like PubNub. Disclaimer - I don't work for PubNub or own stock but have successfully used it in multiple projects. You'll be able to target one or many users this way.
According the the [AWS documentation][1] if you try and create a new Platform Endpoint with the same User Data you should get a response with an exception including the ARN associated with the existing PlatformEndpoint.
It's definitely not ideal, but it would be a round about way of querying the User Data Endpoint attributes via exception.
//Query CustomUserData by exception
CreatePlatformEndpointRequest cpeReq = new CreatePlatformEndpointRequest().withPlatformApplicationArn(applicationArn).withToken("dummyToken").withCustomUserData("username");
CreatePlatformEndpointResult cpeRes = client.createPlatformEndpoint(cpeReq);
You should get an exception with the ARN if an endpoint with the same withCustomUserData exists.
Then you just use that ARN and away you go.