Amplify/React AppSync graphql subscriptions #auth error - graphql

Hello there :slight_smile:
I've a little problem related with the #auth.
(Amplify + React + AppSync)
schema.graphql
type Ticket #model
#auth(rules: [
{allow: owner, provider: userPools},
])
{
id: ID!
status: String!
owner: String!
description: String!
}
build -> schema.graphql
type Subscription {
onCreateTicket(owner: String!): Ticket #aws_subscribe(mutations: ["createTicket"])
onUpdateTicket(owner: String!): Ticket #aws_subscribe(mutations: ["updateTicket"])
onDeleteTicket(owner: String!): Ticket #aws_subscribe(mutations: ["deleteTicket"])
}
All operations (create update etc.) are working fine:
const {data: {listTickets: {items: items, nextToken}}} = await API
.graphql(graphqlOperation(listTickets, {
owner: user.username
})) as GraphQLResult;
except with subscriptions:
const subClient = API
.graphql(graphqlOperation(onUpdateTicket, {
owner: user.username
})) as Observable<object>;
subscription = subClient.subscribe({
next: (data: any) => console.log('subscription data:', data),
error: error => console.warn('subscription error: ', error)
});
The subscription never trigger.
(No errors, no warnings)
Any help would be much appreciated!
Thanks

It was working!!!
I forgot to check "owner" not only in the input* but also in the fields below.
#aws-amplify-devs Could you please add this info to the documentation? :)
Could save many hours.

Related

Prisma - Where selector on type with two unique fields

I'm trying to implement resolver which will check if the user with given login exists in the database. But I have a hard time with where selector in Prisma.
So I have the type User:
type User {
UserID: ID! #id
Login: String! #unique
Password: String!
Phone: String!
Mail: String!
Comments: [Comment!]
#relation(
name: "AllCommentsOfUser"
fields: [UserID]
references: [CommentID]
)
Likes: [Like!]
#relation(name: "AllLikesOfUser", fields: [UserID], references: [LikeID])
createdAt: DateTime! #createdAt
}
This is the query generated by Prisma
user(where: UserWhereUniqueInput!): User
input UserWhereUniqueInput {
UserID: ID
Login: String
}
In the login function am trying to check if the user with given login exist in my database:
async login(parent, { email, password, username }, ctx, info) {
const user = await ctx.prisma.user({ username }); // Option 1
const user = await ctx.prisma.user({ Login: username }); // Option 2
if (!user) {
throw new Error(`No such user found for email: ${username}`);
}
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET),
user,
};
},
},
Each time I'm ending up with following error message:
You provided an invalid argument for the where selector on User. Please provide exactly one unique field and value.

Creating two types of data at once in a single resolver (Graphql + Prisma)

When a user creates a data of type Post, I need the graphql server to automatically create a data of type Commit as well. The type Commit connects to type User and type Post. Here is the graphql pattern for type User, type Post, and type Commit:
type User {
id: ID!
username: String!
commits: [Commit!]!
}
type Post {
id: ID!
title: String!
content: String
commits: [Commit!]!
}
type Commit {
id: ID!
user: User!
post: Post!
}
So I made a createPost mutation. The createPost mutation must do two jobs at once: creating the Post, and then creating the Commit. The Commit data should connect to the newly created Post data. Below is the resolver that I have came up with until now:
Mutation: {
createPost: async (_, args) => {
const {user, title, content} = args;
await prisma.createPost({
title,
content
});
const postId = await prisma.post({title}).id();
await prisma.createCommit({
user: {connect: {id: user.id}},
post: {connect: {id: postId }}
});
const newPost = await prisma.post({id:postId});
return newPost;
}
}
Is this an effective way? Or is there a better way to do this?
I think this would work as well:
Mutation: {
createPost: async (_, args) => {
const {user, title, content} = args;
const post = await prisma.createPost({
title,
content
});
await prisma.createCommit({
user: {connect: {id: user.id}},
post: {connect: {id: post.id }}
});
return post;
}
}
Prisma returns the record created so you don't need to query for it again.

Nested GraphQL mutations with AWS Amplify

I'm struggling to write a nested GraphQL mutation for a React Native app I'm building with GraphQL client being AWS Amplify API. Here's my type definition file
type Game #model {
id: ID!
gameId: String!
players: [Player!]!
}
type Player #model {
id: ID!
username: String!
}
Here's my attempt to create a mutation to create a new Game
import API, { graphqlOperation } from '#aws-amplify/api';
const CreateGame = `
mutation ($gameId: String! $username: String!) {
createGame(input: {
gameId: $gameId,
players: [{ username: $username }]
}) {
id
gameId
players
}
}
`;
const gameObj = {
gameId: 'example_game_id',
username: 'example_username'
};
const queryResp = await API.graphql(graphqlOperation(CreateGame, gameObj));
console.log(queryResp.data);
Here's the error I get
"Validation error of type WrongType: argument 'input' with value 'ObjectValue{objectFields=[ObjectField{name='gameId', value=VariableReference{name='gameId'}}, ObjectField{name='players', value=ArrayValue{values=[ObjectValue{objectFields=[ObjectField{name='username', value=VariableReference{name='username'}}]}]}}]}' contains a field not in 'CreateGameInput': 'players' # 'createGame'"

GraphQL Query returning null. Not sure why though [duplicate]

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 2 years ago.
I'm having some trouble with a graphQL query returning null and i'm not quite sure why its returning null. I've read several posts similar to this post but none of those posts have helped identify my exact problem.
I think it has something to do with how i'm passing/getting parameters, since my query with no parameters works fine, but i'm not sure since I can't find any other examples online.
Any help would be greatly appreciated.
I'm using apollo-server, graphql, and a community SQL datasource implementation which uses Knex to create a database connection.
There are two queries I can make.
allParts() - this query works as expected and returns all parts in my database with requested graphQL fields
getPart(itemnum) - this is the query that is not currently working.
graphQL Query:
query{
getPart(itemnum: "T|0000000000001"){
desc
}
}
graphQL response:
"message": "Cannot return null for non-nullable field Part.desc.",
SQL query that is being executed based on Knex debug message:
method: 'select',
options: {},
timeout: false,
cancelOnTimeout: false,
bindings: [ 'T|0000000000001' ],
__knexQueryUid: '3a8234eb-0a5c-46db-ad8e-5508288c9a86',
sql: 'select * from `part` where `itemnum` = ?'
index.js:
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require ('./resolvers')
const PartAPI = require ('./datasources/partAPI');
const knexConfig = {
client: "sqlite3",
connection: {
/* CONNECTION INFO */
filename: "./TEAM_material.db3"
},
debug: true
};
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
partAPI: new PartAPI(knexConfig),
}),
introspection: true,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
partAPI.js:
const { SQLDataSource } = require("datasource-sql");
const MINUTE = 60;
class PartAPI extends SQLDataSource {
getPart(itemnum){
return this.knex.select('*').from('part').where({itemnum});
}
getAllParts(){
const query = this.knex.select('*').from('part').cache(MINUTE);
console.log (query);
return query;
}
}
module.exports = PartAPI;
schema.js
// src/schema.js
const { gql } = require('apollo-server')
const typeDefs = gql`
#Types
type Part {
itemnum: String!
desc: String!
vendor: String!
manuf: String!
venlist: Float!
price: Float!
teamlist: Float!
teamsell: Float!
unitypart: String!
pkgqty: Int!
ioType: String!
preferred: Boolean!
filterlvl1: String!
filterlvl2: String!
filterlvl3: String!
filterlvl4: String!
ipwiretype: String!
opwiretype: String!
obsolete: Boolean!
}
#Queries
type Query {
getPart(itemnum: String!): Part
allParts: [Part!]!
}
`;
module.exports = typeDefs
resolvers.js
// src/resolvers.js
const resolvers = {
Query: {
getPart: (_,args,{dataSources}) => dataSources.partAPI.getPart(args.itemnum),
allParts: (_,__,{dataSources}) => dataSources.partAPI.getAllParts(),
},
};
module.exports = resolvers
turns out my schema was incorrect. The getPart query was expecting a Part but instead my query was returning an array of Part.
old Schema
#Queries
type Query {
getPart(itemnum: String!): Part
allParts: [Part!]!
}
`;
new Schema
#Queries
type Query {
getPart(itemnum: String!): [Part]!
allParts: [Part!]!
}
`;

GraphQL resolver for certain field not being invoked

I wrote simple GraphQL schemas and resolvers in studying purpose, and I could not get reason why my codes work as expected. I used Prisma for ORM, and express-graphql and graphql-import to compose the API.
type User {
id: ID!
name: String!
}
type Link {
id: ID!
url: String!
user: User!
}
type Query {
links(id: ID!): [Link!]!
}
// resolvers
const links = async (root, args, ctx) => {
const links = await ctx.prisma.links({
where: {
user {
id: args.id
}
}
}
}
// resolver for `Link` type
const user = async (root, args, ctx) => {
const user = await ctx.prisma.link({ id: parent.id }).user()
return user
}
// omitted field resolver for `url` and `id`
module.exports = {
user
}
With these codes, I expected to get id, url, user fields when I query links, but when I send the query, it returns null with user field. Which means, if I check in the server-side, the resolver for user field does not invoked at all. What is wrong with this?

Resources