amplify-category-api
amplify-category-api copied to clipboard
How do we point two different types to the same DynamoDB table?
For new Amplify (>=7.5.0), how do we point two different types to the same DynamoDB table? Couldn't find this anywhere in the docs.
For example, how can I have both User and UserPublic read/mutate the same DynamoDB table? I tried mucking around with CustomResources.json, but couldn't get it to work:
type User @model {
name: String
ssn: String
}
type UserPublic @model {
name: String
}
Thank you!
Can you explain your use case a bit more. It seems like this problem could be solved by using auth to control access to a single table.
@cjihrig There are plenty of use cases that cannot be solved with @auth. Whenever my signed-in users need more than 2 groups of access, I am stuck.
Example 1:
Take a User model in a basic social network. Consider User A:
- User A needs full access to User A model:
@auth(rules: [{ provider: userPools, allow: owner }])
- Friends of User A need partial access to User A model
- Non-friends of User A need light access to User A model:
@auth(rules: [{ provider: userPools, allow: private, operations: [read] }])
- Guest users have no access to User A model:
@auth(rules: [{ allow: public, operations: [] }])
There is no way for me to setup permissions for (2) using @auth. But with a secondary type UserForFriends pointing at Users table, it's trivial:
type User @model @auth(rules: [{ provider: userPools, allow: owner }]) {
name: String
favoriteMovie: String
ssn: String
}
type UserForFriends @model @auth(rules: [{ provider: userPools, allow: private, operations: [read] }]) {
name: String
favoriteMovie: String
}
type UserPublic @model @auth(rules: [{ provider: userPools, allow: private, operations: [read] }]) {
name: String
}
Example 2:
Take a User model in a basic dating app (e.g. Tinder). Consider User A:
- User A needs full access to User A model:
@auth(rules: [{ provider: userPools, allow: owner }])
- Matched users need partial access to User A model
- Potential matches need light access to User A model:
@auth(rules: [{ provider: userPools, allow: private, operations: [read] }])
- Guest users have no access to User A model:
@auth(rules: [{ allow: public, operations: [] }])
Same as above, there is no way for me to setup permissions for (2) using @auth. But with a secondary type UserForMatched pointing at Users table, it's trivial.
I just tried another approach, using amplify override api
with override.ts
, but it didn't work either:
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
resources.models["UserPublic"].modelDDBTable = resources.models["User"].modelDDBTable
resources.models["UserPublic"].modelIamRole = resources.models["User"].modelIamRole
resources.models["UserPublic"].dynamoDBAccess = resources.models["User"].dynamoDBAccess
resources.models["UserPublic"].modelDatasource = resources.models["User"].modelDatasource
}
How do I do this? Please, help.
There are plenty of use cases that cannot be solved with @auth. Whenever my signed-in users need more than 2 groups of access
Sorry, I was referring to field level auth. Have you looked into that at all?
@cjihrig Yes, I have looked at field level auth. Whether I use model- or field-level auth, it doesn't help when I have 3+ groups of signed-in users.
Taking example (1) above, I have the owner with allow: owner
permissions, a signed-in user with allow: private
permissions, but I don't have allow: friends
permissions for owner's friends.
Right now, to create allow:friends
permission, I have to
- Create a custom authorizer that checks whether two users are friends.
- Create a custom allow/deny fields resolver.
If I could point two types at the same AppSync datasource, then I could skip step (2) while making the interface for allow: friends
permission explicit in schema.graphql
.
I'm landing here because I'm trying to implement a dual approval strategy where only one user can initiate the approval process.
My idea of schema.graphql
is:
type sendApproval @model(subscriptions: null, timestamps: {createdAt: "createdAt", updatedAt: "sendUpdatedAt" }) @auth(rules: [{ allow: owner, ownerField: "sendOwner"}]) {
id: ID!
sendOwner: String!
rcptOwner: String!
contractId: String!
sendStatus: sendStatusType!
createdAt: AWSDateTime
sendUpdatedAt: AWSDateTime
}
type rcptApproval @model(subscriptions: null, timestamps: {createdAt: "rcptCreatedAt", updatedAt: "rcptUpdatedAt" }) @auth(rules: [{ allow: owner, operations: [read], ownerField: "rcptOwner"}]) {
id: ID! @auth(rules: [{ allow: owner, operations: [read]}])
rcptOwner: String! @auth(rules: [{ allow: owner, operations: [read]}])
rcptStatus: String @auth(rules: [{ allow: owner, operations: [read,update]}])
rcptUpdatedAt: AWSDateTime @auth(rules: [{ allow: owner, operations: [read,update]}])
sendOwner: String @auth(rules: [{ allow: owner, operations: [read]}])
}
What I've tried is to tweak the table name with override.ts
, but deploy fails with "table already exists" error because amplify is trying to create two tables with the same name.
export function override(resources: AmplifyApiGraphQlResourceStackTemplate, amplifyProjectInfo: AmplifyProjectInfo) {
resources.models["sendApproval"].modelDDBTable.tableName = ApprovalTableName;
resources.models["rcptApproval"].modelDDBTable.tableName = ApprovalTableName;
...
}
Having the possibility to use the same table would be great.