Currently I'm on aws amplify and I have several authorizers (graphql lambda authorizer) but I can't specify the name of the one I want to use for my user table.
Anyone have an idea how to do it?
type User
#model
#auth(rules: [{ allow: custom }])
{
id: ID!
first_name: String
last_name: String
}
Related
I have decided to convert my AWS Amplify application to be built with the AWS CDK instead. I am now faced with converting my schema.graphql to something that can work with the AWS CDK.
I have created two tables below that offer a variety of functionality that comes out of the box with AWS Amplify.
Key Functionality I am stuck on building in the AWS CDK:
#hasMany
#auth
Adding resolvers for CRUD operations
What I have achieved already:
Creating DynamoDB Tables
Creating Global Secondary Indexes
Code:
type EmployerAccount
#model
#auth(
rules: [
{ allow: owner, operations: [create, update, delete, read] }
{ allow: private, operations: [read] }
{ allow: public, provider: iam, operations: [read] }
]
) {
id: ID!
owner: String!
group: String
#index(
name: "byEmployerGroup"
queryField: "byEmployerGroup"
)
images: [Image] #hasMany(indexName: "byEmployer", fields: ["id"])
}
type Image
#model
) {
id: ID! #primaryKey(sortKeyFields: ["employerID"]) #IMAGE-ksuid
employerID: ID! #index(name: "byEmployer", queryField: "byEmployer", sortKeyFields: ["id"])
}
I have decided to use:
#aws-cdk/aws-appsync-alpha module
aws-cdk-lib (V2 of the CDK)
I am a bit confused about how authentication works using AWS Amplify (Cognito and AppSync bundle).
I have setup my authentication method to Cognito and I designed a datamodel using GraphQL API schema.
It looks almost like this (I skipped some elements has they are not relevant to my question):
type Grower #model
#auth(rules: [
{ allow: owner, ownerField: "admins" },
{ allow: owner, ownerField: "members", operations: [read, update, create]},
{ allow: owner, ownerField: "guests", operations: [read]}
]) {
code: String!
name: String!
admins: [String]
members: [String]
guests: [String]
workers: [Workers] #hasMany
orchards: [Orchard] #hasMany
}
type Orchard #model
#auth(rules: [
{ allow: owner }
]){
name: String!
location: String
grower: Grower! #belongsTo
harvests: [Harvest] #hasMany
visits: [Visit] #hasMany
}
Given this schema, will a user declared in the Grower.admins field be able to access an Orchard and its fields if it belongs to the Grower?
And, the opposite, will a user not declared as a member of this Grower (neither guests, member or admins) be able to see the Orchard?
Basically, I would like to understand if my authentication rules 'propagate' throught nested models.
Any comment about this datastructure is welcomed.
In my schema.graphql file I have the following:
type Floorplan #model #auth(rules: [
{ allow: private, operations: [read], provider: userPools },
{ allow: owner, provider: userPools }
]) #aws_cognito_user_pools {
id: ID! #primaryKey
name: String!
bedrooms: Int!
}
input FloorplanInput {
id: ID!
name: String!
bedrooms: Int!
}
type Mutation {
floorplanLambda(input: FloorplanInput): Floorplan
#function(name: "floorplanLambda-${env}")
#aws_cognito_user_pools
}
I created the lambda function to perform custom validation before updating.
The problem is that any authenticated user can update other users' floor plans. I thought adding #aws_cognito_user_pools would resolve this, but it doesn't.
Question: What do I need to add to lock down the floorplanLambda function so that it can only be successfully called by the owner of the Floorplan model?
When calling floorplanLambda I receive the error: "Not Authorized to access floorplanLambda on type Floorplan". I'm making the call with authMode AMAZON_COGNITO_USER_POOLS.
For some more context, I followed this tutorial to create the custom mutation lambda function: https://www.theclouddeveloper.io/use-lambda-resolvers-in-your-graph-ql-api-with-aws-amplify
So according to the response to my GitHub issue, this workflow is not currently supported. You can follow it here: https://github.com/aws-amplify/amplify-category-api/issues/528#issuecomment-1157894170
A workaround was provided by:
...setting the auth rule to private and then perform
validation in the lambda function...
I was thinking to create a custom auth function and then chain it in front of my custom mutation. Not sure if that will work but I'll report back once I've made some progress.
I created a GraphQL api via the amplify api add command and added the schema below. I'm using cognito for auth.
type User #model
#auth(rules: [{ allow: owner }]) {
id: ID!
videos: [Video!] #connection(keyName: "videosByUser", fields: ["id"])
adverts: [Advert] #connection(keyName:"advertsByUser", fields: ["id"])
}
type Video #model
#key(name: "videosByUser", fields: ["userId"])
#auth(rules: [{ allow: owner, operations: [create, update, delete] }]) {
id: ID!
title: String!
description: String!
size: Float!
length: Float!
hashMarks: [Float!]!
userId: ID!
# bidrectional connection, if needed
# user: User! #connection(fields: ["userId"])
adverts: [VideoAdverts!] #connection(keyName: "advertsByVideo", fields: ["id"])
streamingLink: AWSURL
}
type VideoAdverts #model(queries: null)
#key(name: "advertsByVideo", fields: ["videoId", "advertId"])
#key(name: "videosByAdvert", fields: ["advertId", "videoId"]) {
id: ID!
videoId: ID!
advertId: ID!
video: Video! #connection(fields: ["videoId"])
advert: Advert! #connection(fields: ["advertId"])
}
type Advert #model
#key(name: "advertsByUser", fields: ["userId"])
#auth(rules: [{ allow: owner, operations: [create, update, delete] }]) {
id: ID!
title: String!
description: String!
size: Float!
length: Float!
creatorId: ID!
# bidrectional connection, if needed
# creator: Creator! #connection(fields: ["creatorId"])
videos: [VideoAdverts!] #connection(keyName: "videosByAdvert", fields: ["id"])
blacklist: [AdvertBlacklist!] #connection(keyName: "blacklistByAdvert", fields: ["id"])
startDate: AWSDateTime
endDate: AWSDateTime
}
This is my first amplify project and I'm having trouble figuring out how to implement the following use cases:
Use a lambda function to query data and return to a client.
Use a cron triggered lambda function to make an API call and use a mutation to update some fields.
All I have found so far from googling involves using lambdas to interact with data added via the amplify storage add command.
A few other examples I found here on Stackoverflow do not use cognito for auth.
Looks like I will be able to use cloudwatch to trigger lambdas, and so my main problem now is how to actually query and mutate a GraphQL api from a lambda, using cognito for authentication.
Any help would be super helpful, thanks :)
The key to authenticating your Lambda functions to interact with your AppSync API is to configure multiple authentication methods. You are using Cognito for your front end application users, however, you do not want to use that for your Lambda function authentication. AppSync supports multiple authentications mechanisms for your API. In your case, you will want to add IAM as the second authentication mechanism.
You can do this from the Amplify CLI:
$ amplify update api
Scanning for plugins...
Plugin scan successful
? Please select from one of the below mentioned services: GraphQL
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Do you want to configure advanced settings for the GraphQL API Yes, I want
to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API IAM
AWS-Amplify provides a couple of directives to build an GraphQL-API. But I haven't found out how to ensure uniqueness for fields.
I want to do something like in GraphCool:
type Tag #model #searchable {
id: ID!
label: String! #isUnique
}
This is an AWS-Amplify specific question. It's not about how to do this with generic GraphQL. It's very specifically about how to do this with AWS-Amplify's API module. (https://aws-amplify.github.io/docs/js/api)
Hey thanks for the question. This is not yet possible by default using the amplify-cli but you could do this yourself using pipeline resolvers and an extra index on your DynamoDB table. The steps to do this are as follows:
Create a GSI on the table where the label is the HASH KEY.
Create a pipeline resolver on the Mutation.createTag field in your schema. You can turn off the auto-generated Mutation.createTag mutation by changing your #model definition to #model(mutations: { update: "updateTag", delete: "deleteTag" }).
Create a function named LookupLabel that issues a Query against the new GSI where the label = $ctx.args.input.label. If this returns a value, throw an error with $util.error("Label is not unique"). If it returns no values then continue.
Create a function named CreateTag that issues a PutItem against the Tag table.
Add those two functions in order to your pipeline resolver.
You can read more about pipeline resolvers here https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html.
As of writing amplify does not yet support custom & pipeline resolvers but you can read more about the feature here https://github.com/aws-amplify/amplify-cli/issues/574 as it will be supported in the future. For now you can add the resolver manually in the AWS AppSync console or via your own CloudFormation template that targets the id of the API created by Amplify. It would also be helpful if you create an issue here (https://github.com/aws-amplify/amplify-cli/issues) and tag this as a feature request because it would be possible to automate this with an #unique directive but this would need to be planned.
Thanks
Update: now you can use #primarykey and #index annotations:
https://docs.amplify.aws/cli/migration/transformer-migration/#what-is-changing
basic:
profile #model {
name
email #primaryKey - has to be unique
other
}
so if you needed something like:
profile #model {
name
email: String! #hasOne
other
}
email #model {
email: String! #primaryKey
}
if you are on an older version see below
I will eventually be testing this out to see if this works but you might be able to do something like rename the id to a string!
so...
type Tag #model #key["id"] {
id: String!
}
or:
type Customer #model #key(fields: ["email"]) {
email: String!
username: String
}
this second one is taken directly from the docs: https://docs.amplify.aws/cli/graphql-transformer/key#designing-data-models-using-key
The docs were updated recently so hopefully they are easier for everyone to understand.
If you need a more advanced workflow with allot of keys, and stuff like that then you just have to separate things out and make more types for example:
type Customer #model {
id: String!
email: Email! #hasOne
username: String
}
type email #model #key(fields: ["email"]) {
email: String!
}