How to get the current user from a Lambda resolver in AWS Amplify (GraphQL api and NodeJS Lambda)? - aws-lambda

I have a graphql Api and added a lambda function to resolve a mutation.
type Mutation {
addTeamMember(email: String!, teamId:ID!): String #function(name: "add-team-member-${env}")
}
From the lambda I want to retrieve the authenticated user that sent the request to perform additional validations, ¿How to retrieve it from the request information?
strong text

I printed the contents of the first lambda parameter and found it:
Access it with:
event.identity.username

Related

Authorize based on field value in another document in AppSync GraphQL custom authentication via Lambda Resolver

I am new to Amplify Datastore & AppSync w/ GraphQL, but in Firestore, you can write an auth rule like: allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true [https://firebase.google.com/docs/firestore/security/rules-conditions#access_other_documents] -> which would grab the document at /users/{id}/ and I can access the admin field to write a security rule logic.
How do you do the same in a Lambda function resolver?
I am aware that the solution may involve a Lambda resolver (https://stackoverflow.com/a/68581796/9824103) but I cannot find any reference to reading a specific document and doing logic to authorize or deny an operation based on a field value in a document. I am only asking how to do this specific thing. Thank you!
I followed https://docs.amplify.aws/cli/graphql/authorization-rules/#custom-authorization-rule to create a custom authorization rule via adding the #rule directive: type MyModel #model #auth(rules: [{ allow: custom }]) and.. although the lambda function isn't really getting called when I try to write a listMyModel or createMyModel (any hints as to why that would be great), I am focused on writing the lambda function to read query a document and check a certain field to meet my custom auth condition.
fyi, I am using Flutter based amplify-cli.

How to create a custom, hardcoded health check GraphQL query with AWS Appsync?

I'm new to AWS Appsync and to GraphQL.
Previously, I used to create REST APIs in Python. I was always creating a GET /health-check endpoint, sending back, for example and among many other info, the API version number, easily parsed from the project descriptor pyproject.toml file.
That helped me massively to maintain APIs: with a single GET query in my browser, I was always able to instantly get if branch/version it was, the status of other services, etc. .
I want to do something similar with AWS Appsync / GraphQL and my IaC tool (Pulumi).
Since I'm using IaC tool Pulumi in Python, I could still easily get the info I need and inject them in any resolver response template.
But if I create a resolver, should I create a corresponding health-check query itself in the GraphQL schema? When creating a resolver with a hardcoded JSON response, should it be associated with a GraphQL query in the schema, and if yes, how should that query in the schema look like?
I finally found a way, but it's a very ugly workaround since AppSync VTL resolvers have a lot of limitations and since I'm using Pulumi as a Iac tool which also doesn't accept all arguments when creating a resolver - for example for GetItem operation it needs an id key in the request template.
I'm posting the workaround here anyway if it can be of any help to someone.
GraphQL schema:
schema {
query: Query
}
type Query {
getHealthCheck: String
}
AppSync getHealthCheck resolver request template:
{
"version": "2018-05-29",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson(""),
},
}
AppSync getHealthCheck resolver response template example:
"'version':'0.1', 'branch':'staging', 'commitId':'abc123'"
So in a IaC tool like Pulumi using Python, one could build the response template like that:
"""
"'version':'{}', 'branch':'{}', 'commitId':'{}'"
""".format(
version,
os.environ.get("GITHUB_REF_NAME", "unknown"),
os.environ.get("GITHUB_SHA", "unknown"),
),

Is it possible to map a subscription parameter to an array at the mutation output?

I have a theoretical question. As I know subscription parameters must exist as a field in the returning type of the mutation. This means that the type of parameter must also match the type of the field in the returning object of the mutation. Am I right? Suppose I get an array with channels ids in the mutation response. I only send one channel id as a parameter in the subscription. Is it possible to map a subscription parameter to an array at the mutation output? If the channel id exists in the array (field channelsIds), the subscription must work. Is it possible to write this logic in the scheme itself, or is it technically impossible?
GraphQL schema:
schema {
mutation: Mutation
subscription: Subscription
}
type Mutation {
testMutation(input: TestMutationInput): TestMutationOutput
}
type TestMutationOutput {
channelsIds: [String!]!
userId: String!
userEmail: String
userPhoneNumber: String
}
type Subscription {
watchTestMutation(channelId: String!): TestMutationOutput
#aws_subscribe(mutations: ["testMutation"])
}
If I understand you correctly you want to filter based on if the mutation's returned value is in an array that is passed as an argument to the subscription. Sorry to say that is not possible at this time. Subscription filters only evaluate to true or false and cannot accommodate any logic other than that.
At the end of October 2020, I contacted AWS support for advice on this issue. I think this answer may be useful to someone, so I post their answer.
Please allow me to inform you that the use-case that you have
mentioned in the case is currently not possible via AppSync. I
understand that the lack of the feature may be causing inconvenience.
There is an internal feature request already with the AppSync team to
incorporate this feature and I have added a +1 on your behalf. It is
worth noting, that once this feature request is with the team, it will
be up to the team as to if/when this potential infrastructure feature
is implemented, and because of the limited visibility into the
progress of internal development processes, I won’t be able to provide
an ETA regarding its release. I would request you to keep an eye on
the what's new page or the AWS Blogs as all new feature requests and
enhancements are posted there[1-3].
However we can suggest a couple of workarounds in this case:
Filter the required fields on client side itself after receiving the values on the client-side from AppSync.
If the values to be filtered are very limited we can use a fake mutation made with the help of a resolver mapped to “None” Data
source. In this flow, we would create a lambda function that uses a
DynamoDB stream as the trigger. The Lambda function is triggered
whenever there's an update to the DynamoDB table.

We can then include logic in the Lambda function to filter the
required fields and perform a mutation to AppSync. In AppSync, the
mutation which was called by lambda would configured using a resolver
mapped to a “None” Data source. The None data source type passes the
request mapping template directly to the response mapping template.
And when we subscribe to this mutation, we will directly get the
filtered data from Lambda that was used to call this mutation. Please
refer to [4] for a step-by-step description of this process.
But please note that this workaround is cumbersome and would require a lot of changes if the required field values keep changing. Workaround 1(handling it on the client-side) is usually the preferred way to handle this use-case.
Resources:
[1] https://blogs.amazon.com/
[2] https://aws.amazon.com/new/
[3] https://aws.amazon.com/releasenotes/
[4] https://aws.amazon.com/premiumsupport/knowledge-center/appsync-notify-subscribers-real-time/

Graphql query resolvers split into seperate lamdas

I am writing a serverless app using aws lambdas. we are using apollo graphql for single endpoint. graphql endpoint run in one single lamda, how can i split graphql query mutation resolvers into seperate lamda functions, like in graphcool and aws app-sync.
AWS AppSync has the concept of Datasources which can be individual Lambda functions (or you can use DynamoDB tables or Elasticsearch domains). In your GraphQL schema you would then attach a resolver to a field (like a query or mutation) and this resolver would invoke the Lambda datasource. AppSync lets you do this as a single Lambda invocation or "BatchInvoke" for having the Lambda hit multiple resources and return a LIST.
The resolver template (written in Velocity Template Language) is fairly straightforward to send your GraphQL request on through to Lambda, and adding this is a drop down selection from the samples in the console:
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": $util.toJson($context.arguments)
}
You can read more about this here: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html
As of now, the only way to do it on Apollo is to call your Lambdas by their URIs. The good about this is that you can cache their responses. The bad part is that you can't have a pure GraphQL environment.

Can API-Gateway check the input parameters and reject (without passing it to Lambda) an HTTP request?

I would like to use API-Gateway (plus Lambda) to realize a PetStore Restful API. One of the API entry point is and the body of the POST request needs to contain 'name'. See the PetStore definition snippet below:
/pets/
POST
definitions:
NewPet:
required:
- name
properties:
name:
type: string
tag:
type: string
Can I make API-Gateway smart enough to reject requests that does not contain the required field (in this case, 'name'), without calling the Lambda (yes, I understand I am able to check the input fields inside the Lambda function, but I wonder if I can avoid it)? -- this would save a lot of time and complexity to deal with the corner case.
This can be achieved through using request validation set in the "method request" settings.
If you want to validate the request body rather than query string you need to create a model;
APIs > {ApiName} > Models
In the sidebar.
Create your model using JSON Schema
In the API Gateway, choose to validate the request body then select your created model in the dropdown.
API Gateway config page

Resources