AWS AppSync Mapping Template DynamoDB Query doesn't work - graphql

I'm using AWS CDK version 2.64.0 to configure AWS AppSync to setup my GraphQL API.
I created my graphql.schema with the following configuration:
type message {
id_message: String!
id_collection: String!
id_user: String!
created_at: String!
text: String!
}
type Query {
getMessages(idCollectionIdUser: String!): [ message! ]
}
And then I used the configuration above to create my GraphQL API using these commands:
const api = new appsync.GraphqlApi(this, 'GraphQLDatabase', {
name: 'my-graphql-database',
schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema.graphql')),
xrayEnabled: true,
});
I also created one dynamodb table (with one global secondary index) using the following commands:
const messageTable = new dynamodb.Table(this, 'MessageTable', {
partitionKey: {
name: 'id_message',
type: dynamodb.AttributeType.STRING,
},
tableName: 'message.dynamodb-table',
removalPolicy: RemovalPolicy.DESTROY,
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
messageTable.addGlobalSecondaryIndex({
indexName: 'id_collection-id_user-created_at-index',
partitionKey: {
name: 'id_collection-id_user',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'created_at',
type: dynamodb.AttributeType.NUMBER,
},
projectionType: ProjectionType.ALL,
});
Then I added the dynamodb table as datasource for the graphql database:
const messageDataSource = api.addDynamoDbDataSource('messageDataSource', messageTable);
I'm now trying to create a resolver to get all the messages created by the user in a collection with the following code:
messageDataSource.createResolver('QueryGetMessagesResolver', {
typeName: 'Query',
fieldName: 'getMessages',
requestMappingTemplate: appsync.MappingTemplate.dynamoDbQuery(
appsync.KeyCondition.eq('id_collection-id_user', 'idCollectionIdUser'),
'id_collection-id_user-created_at-index',
false,
),
responseMappingTemplate: appsync.MappingTemplate.dynamoDbResultList(),
});
When I test my graph api, I always get this error:
ExpressionAttributeNames contains invalid key: Syntax error; key: "#id_collection-id_user"
What am I doing wrong?

Related

cannot delete a product from db using graphql

Schema:
type Mutation {
removeProduct(id: String!): Product
}
type Product {
id: ID!
name: String!
slug: String!
description: String!
price: Float!
image: String!
ingredients: [String]
addOns: [String]
}
resolver:
exports.Mutation = {
removeProduct: async (parent, { id }, { Product }) => {
const deletedProduct = await Product.deleteOne({ id });
return deletedProduct;
},
};
query:
mutation{
removeProduct(id:"b55572b9-eb4d-46ea-a82f-f01cb0ba3993")
{
id
name
}
}
I need to remove a product from the db, but while deleting it, the response from graphql shows that "message": "Cannot return null for non-nullable field Product.name.",
It maybe because the product is deleted and nothing is returned because there is no product in db.
How do I write a query to delete a product ?
Note that it deletes the product from the db, but shows error in graphql response.

Iterate Over Custom Directives in GraphQL Schema

I have a simplified schema.graphql file with one type and one custom directive (at the field and object level). In Typescript, how can I programmatically get the type and type directive, and iterate over the fields and field directives?
type Test #myCustomDirective() {
id: String! #myCustomDirective()
}
This post says "This is not currently supported by GraphQL":
Is there any way to read GraphQL Directives on a Type with Query Introspection?
And the GitHub issue says this feature is being considered:
https://github.com/graphql/graphql-spec/issues/300
Then how is AWS AppSync doing this? See below.
// The following keeps custom directives:
parse(schema); // Return type: graphql.DocumentNode
// The following removes custom directives:
buildSchema(schema); // Return type: GraphQLSchema
AWS AppSync > Export Schema > Schema.json does include custom directives but is an AWS AppSync specific solution and is an expensive API operation.
aws appsync get-introspection-schema --api-id abc123 --format JSON --include-directives output.json
I tried GraphQL Code Generator Introspection plugin. But it removes custom directives from types and fields.
https://www.graphql-code-generator.com/plugins/introspection
I tried graphql/utilities but it also removes custom directives from types and fields.
graphql.introspectionFromSchema(graphqlSchema)
// or
graphql.graphqlSync({ schema: graphqlSchema, source: graphql.getIntrospectionQuery() }).data as unknown as graphql.IntrospectionQuery;
https://graphql.org/graphql-js/utilities/
This "GraphQL Tools" approach creates an iteratable schema but may not be the most efficient approach:
"The graphql-tools package allows you to create a GraphQL.js GraphQLSchema instance from GraphQL schema language using the function makeExecutableSchema"
https://www.graphql-tools.com/docs/generate-schema
import { promises as fs } from 'fs';
import { makeExecutableSchema } from '#graphql-tools/schema';
import gql from 'graphql-tag';
const schemaFile = await fs.readFile(
'./schema.graphql'
);
const executableSchema = makeExecutableSchema({
typeDefs: gql(schemaFile.toString())
});``
const output = executableSchema.getType('Test');
// output.astNode.directives sample output:
{
kind: 'Directive',
name: { kind: 'Name', value: 'myCustomDirective1' },
arguments: [ [Object] ]
},
{
kind: 'Directive',
name: { kind: 'Name', value: 'myCustomDirective' },
arguments: [ [Object] ]
}
// output.astNode['fields'] sample output:
[{
kind: 'FieldDefinition',
description: undefined,
name: { kind: 'Name', value: 'id' },
arguments: [],
type: { kind: 'NamedType', name: [Object] },
directives: [ [Object] ]
}]

How to defined non-null elements inside an array in GraphQL Nexus?

I'm using GraphQL Nexus to implement my GraphQL schema.
The target GraphQL type I want to create is this:
input UserCreateInput {
email: String!
name: String
posts: [PostCreateInput!]!
}
However, I'm not sure how I can create the PostCreateInput array such that the elements of the posts are are required as well.
Right now this is what I have:
input UserCreateInput {
email: String!
name: String
posts: [PostCreateInput]!
}
Which is backed by this Nexus type definition:
const UserCreateInput = inputObjectType({
name: 'UserCreateInput',
definition(t) {
t.nonNull.string('email')
t.string('name')
t.nonNull.list.field('posts', {
type: 'PostCreateInput',
})
},
})
Is there a way how I can tell Nexus that each array element should be non-null?
In this case, adding a nonNull after the list should suffice. So something like the following:
const UserCreateInput = inputObjectType({
name: 'UserCreateInput',
definition(t) {
t.nonNull.string('email')
t.string('name')
t.nonNull.list.nonNull.field('posts', {
type: 'PostCreateInput',
})
},
})

prisma.exists method not working with mongodb Atlas

i am using prisma image 1.34
I have a small issue trying to implement the prisma.exists method with mongodb atlas.
type Business {
_id: ID! #id
name: String!
desc: String!
published: Boolean!
author: User! #relation(name: "BusinessUser", link: INLINE)
async updateBusiness(parent, args, { prisma, request }, info) {
const postExists = await prisma.exists.Business({
_id: args.id,
})
if (!postExists) {
throw new Error('Unable to update post')
}
return prisma.mutation.updateBusiness({
where: {
_id: args.id
},
data: args.data
}, info)
}
}
the error I got is
TypeError: Cannot read property 'length' of undefined
at C:\Users\jarid\Desktop\Alfarouk\alfarouq\Backend\node_modules\prisma-binding\src\Prisma.ts:86:31
at process._tickCallback (internal/process/next_tick.js:68:7)
when I remove the code related to prisma.exists the resolver runs successfully , also I did verify that the argument "args.id" is pulled successfully
**Versions
Prisma Server: [1.34.1]
prisma CLI: [1.34.1 ]
OS: [Windows 10 home edition]
docker toolbox
Are you using the client or the bindings? According to the prisma documentation the syntax should be as follows:
const userExists = prisma.$exists.user({
id: 'cjli6tko8005t0a23fid7kke7',
})
See: https://www.prisma.io/docs/1.34/prisma-client/features/check-existence-JAVASCRIPT-pyl1/
I had the same problem. The Documentation is not correct.
The exists function is called in the wrong way.
Try this. it should work...
const userExists = prisma.user({
id: 'cjli6tko8005t0a23fid7kke7',
}).$exists

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