Amplify - Custom status code from Graphql lambda function - aws-lambda

I am currently using a lambda function attached to my graphql createUser.
schema.graphql
type User
#model(queries: { get: null }, mutations: null, subscriptions: null)
#auth(rules: [
{ allow: groups, groups: ["ADMIN"] }
])
{
id: ID!
first_name: String!
last_name: String!
email: String!
}
createUser(input: CreateUser!): User
#function(name: "createUser-${env}")
#auth(rules: [
{ allow: groups, groups: ["ADMIN"] }
])
I'm trying to return a 401 status code from my lambda but it's not working, how can I do that ?

Related

AppSync / Apollo - Subscription - Update nested array within a model

For a Chat app I am trying to update the Apollo cache for a nested array, so that when a message is received for any conversation, the user can see the latest message in real time.
I have the following AppSync schema.
type Conversation
#model
#auth(rules: [
{ allow: owner, ownerField: "users", operations: [create, read, delete, update] }
{ allow: private, provider: iam, operations: [read, create, update, delete] }
]) {
messages: [Message] #hasMany(indexName: "messagesByConversation", limit: 1)
users: [String]
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
type Message
#model(mutations: { create: "createMessage", update: "updateMessage" })
#auth(rules: [
{ allow: groups, groups: ["Users"] }
{ allow: owner, operations: [read, create, update], ownerField: "users" }
{ allow: private, provider: iam }
]) {
conversationId: ID! #index(name: "messagesByConversation", sortKeyFields: ["createdAt"], queryField: "messagesByConversation")
text: String
users: [String]!
receiver: ID!
sender: ID!
createdAt: AWSDateTime!
updatedAt: AWSDateTime
}
type Subscription {
onCreateMessageForSenderUser(sender: String!): Message #aws_subscribe(mutations: ["createMessage"])
onCreateMessageForReceiverUser(receiver: String!): Message #aws_subscribe(mutations: ["createMessage"])
}
Which has the nested model messages: [Message]
In the Apollo Cache, I can see a new typename is created called __ ModelMessageConnection to facilitate the connection
I have a subscription that listens for new messages (in this case when my user is the sender).
The trouble I am facing, is how can I update the cache so when the subscription for a new message is received, it updates for the conversation (the ModelMessageConnection)
const { data: senderMessageData } = useSubscription(
gql(SENDER_MESSAGE_SUBSCRIPTION),
{
skip: !subData?.sub,
variables: {
sender: subData?.sub
},
onSubscriptionData: (options) => {
options.client.cache.modify({
//TODO: do something here?
});
}
}
);

Appsync & GraphQL: how to sort a list by nested value

I have an Appsync API generated by Amplify from a basic schema. On the SocialMediaDocument model, a ctr field is nested within a stats field. I want to build a Query that provides a list of SocialMediaDocument sorted by ctr. Is this possible ? Or should I sotre the ctr on my SocialMediaDocument ?
type SocialMediaDocument
#model
#auth(
rules: [
{ allow: owner, operations: [create, read] }
{ allow: groups, groupsField: "organizationGroupName" }
{ allow: groups, groups: ["Admin"], operations: [create, read, update, delete] }
]
)
#key(
name: "socialMediaDocumentsByCustomerID"
fields: ["customerID", "createdAt"]
queryField: "socialMediaDocumentsByCustomerID"
)
#key(
name: "socialMediaDocumentsByRequestStatus"
fields: ["requestStatus"]
queryField: "sociaMediaDocumentsByRequestStatus"
)
#key(
name: "socialMediaDocumentsByOrganizationID"
fields: ["organizationID", "createdAt"]
queryField: "socialMediaDocumentsByOrganizationID"
) {
id: ID!
stats: [SocialMediaDocumentStats!]
}
type SocialMediaDocumentStats {
date: AWSDate
ctr: Float!
engagementRate: Float!
postClicksLifetime: Float!
postEngagedUsersLifetime: Float!
postImpressionsLifetime: Float!
}

Authorization error when updating a GraphQL object using aws-amplify

I'm experiencing issues when using aws amplify to generate a graphql API
My model has mainly two objects (User and messages):
User object:
type User
#model(subscriptions: null)
#auth(rules: [{ allow: owner, ownerField: "id" }]) {
id: ID!
email: String!
username: String!
avatar: S3Object
name: String
conversations: [Conversation] #manyToMany(relationName: "UserConversations")
messages: [Message!]! #hasMany(indexName: "byAuthor", fields: ["id"])
createdAt: String
updatedAt: String
}
Message object:
type Message
#model(subscriptions: null)
#auth(
rules: [
{
allow: owner
ownerField: "authorId"
operations: [create, update, delete]
}
]
) {
id: ID!
author: User #belongsTo(fields: ["authorId"])
authorId: ID! #index(name: "byAuthor", sortKeyFields: ["content"])
content: String!
conversation: Conversation! #belongsTo(fields: ["messageConversationId"])
messageConversationId: ID!
#index(name: "byConversation", sortKeyFields: ["createdAt"])
createdAt: String
updatedAt: String
}
There's a hasMany/belongsTo relationship between the two and auth rules on both.
After I signin to the API and try to create a user object through the JS API, i'm getting the following error
'Not Authorized to access messages on type ModelMessageConnection'
await AuthAPI.graphql(
graphqlOperation(createUser, {
input: {
id,
username,
email,
name,
},
})
);
This is actually due to the message rule that was missing the read action. Changing the object model to the code below fixed it
type Message
#model(subscriptions: null)
#auth(
rules: [
{
allow: owner
ownerField: "authorId"
operations: [create, update, delete, read]
}
]
) {
id: ID!
author: User #belongsTo(fields: ["authorId"])
authorId: ID! #index(name: "byAuthor", sortKeyFields: ["content"])
content: String!
conversation: Conversation! #belongsTo(fields: ["messageConversationId"])
messageConversationId: ID!
#index(name: "byConversation", sortKeyFields: ["createdAt"])
createdAt: String
updatedAt: String
}

In an AppSync #auth rule, how do I set an ownerField to a property in an array?

Imagine I have the following AppSync GraphQL schema with a User type, and a Post type with an editors field set to an array of Users:
type User
#model
#auth(rules: [
{ allow: owner }
])
{
id: ID!
owner: String!
username: String!
}
type Post
#model
#auth(rules: [
{ allow: owner },
# Can I do this?
# { allow: owner, ownerField: "editors.owner", operations: [update] }
])
{
id: ID!
owner: String!
title: String!
content: String
editors: [User]
}
How do I create an #auth rule to give update permissions to the Users in the editors array?
If you're using the amazon Cognito user pool you should set the editor type inside Post to be an array of String and set the values to the Cognito ids of the users that you want to have access. This is explained in the amplify cli documentation.
To have the editors to be of type User I suggest you to create another paramether named differently (for example editorUsers) and connect it to the User model as described here
Your schema should look like this:
type User
#model
#key(name: "byUser", fields: ["username"])
#auth(rules: [
{ allow: owner }
])
{
id: ID!
owner: String!
username: String!
}
type Post
#model
#auth(rules: [
{ allow: owner },
{ allow: owner, ownerField: "editors", operations: [update] }
])
{
id: ID!
owner: String!
title: String!
content: String
editors: [String]
editorsUsers: [User] #connection(keyName: "byUser", fields: ["id"])
}

Variable '$_data' cannot be non input type in GraphQL mutation with Prisma

I am using Prisma with GraphQL and get errors when I run the mutatioin.
I deployed prisma succussfully and binded it with local graphQL.
-- datamodel.graphql - prisma setting
type Link {
id: ID! #unique
description: String!
url: String!
postedBy: User
}
type User {
id: ID! #unique
name: String!
email: String! #unique
password: String!
links: [Link!]!
}
-- schema.graphql - local setting
# import Link from "./generated/prisma.graphql"
type Query {
info: String!
feed: [Link!]!
}
type Mutation {
post(url: String!, description: String!): Link!
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
links: [Link!]!
}
Resolver for signup mutation is
async function signup(parent, args, context, info) {
// 1
const password = await bcrypt.hash(args.password, 10)
// 2
const user = await context.db.mutation.createUser({
data: { ...args, password },
}, `{ id }`)
// 3
const token = jwt.sign({ userId: user.id }, APP_SECRET)
// 4
return {
token,
user,
}
}
And this is .graphqlconfig.yml content
projects:
app:
schemaPath: src/schema.graphql
extensions:
endpoints:
default: http://localhost:4000
database:
schemaPath: src/generated/prisma.graphql
extensions:
prisma: database/prisma.yml
GraphQL query I run is .
mutation {
signup(
name: "Alice"
email: "alice#graph.cool"
password: "graphql"
) {
token
user {
id
}
}
}
And the response I got when I run this is
{
"data": {
"signup": null
},
"errors": [
{
"message": "Variable '$_data' cannot be non input type 'UserCreateInput!'. (line 1, column 19):\nmutation ($_data: UserCreateInput!) {\n ^",
"locations": [],
"path": [
"createUser"
]
}
]
}
I can'find the reason of this.
Thank you.
Try use prisma deploy --force
This worked for me.
Fixed it by changing to the right endpoint in index.js
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: req => ({
...req,
db: new Prisma({
typeDefs: 'src/generated/prisma.graphql',
endpoint: 'http://localhost:4466/local/dev',
secret: 'secret',
debug: true,
}),
}),
})
I think your prisma.yml was wrong.
# The endpoint represents the HTTP endpoint for your Prisma API. It encodes
# several pieces of information:
# * Prisma server (`localhost:4466` in this example)
# * Service name (`myservice` in this example)
# * Stage (`dev` in this example)
# NOTE: When service name and stage are set to `default`, they can be omitted.
# Meaning http://myserver.com/default/default can be written as http://myserver.com.
endpoint: http://localhost:4466/myservice/dev

Resources