How do I use schema.graphql file as typeDefs? - graphql

I am learning GraphQL with Node.js and I am currently using graphql-yoga as a GraphQLServer. Now, I want to seperate Type Definitions and Resolvers so I have used schema.graphql and in there I have all my types defined but now I have no Idea how to use that file as typeDefs in GraphQL Server. I have provided my files below.
index.js
const { createServer } = require('graphql-yoga');
const { resolvers } = require('./template1');
const server = createServer({
schema: {
resolvers,
typeDefs: 'src/schema.graphql'
}
});
server.start(() => {
console.log('GraphQL Server started.');
});
schema.graphql
type Query {
hello: String!
posts: [Post!]!
users: [User!]!
comments: [Comment!]!
}
type Mutation {
signUp(data: SignUpInput): User!
createPost(data: CreatePostInput): Post!
createComment(data: CreateCommentInput): Comment!
deleteUser(id: ID!): User!
deletePost(id: ID!): Post!
deleteComment(id: ID!): Comment!
}
input SignUpInput {
email:String!
username: String!
password: String!
}
input CreatePostInput {
title: String!
author: ID!
}
input CreateCommentInput {
text: String!
author: ID!
post: ID!
}
type Post {
id: ID!
title: String!
author: User!
comments: [Comment!]
}
type User {
id: ID!
email: String!
password: String!
username: String!
posts: [Post!]
comments: [Comment!]
}
type Comment {
id: ID!
text: String!
author: User!
post: Post!
}
and I am getting this Error.

Instead of directly passing the schema use:
typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf8'
)

Thanks this worked for me!
Just added this at the top of the file.
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

Related

Why does my deleteComment mutation fail to find the entity to be deleted?

I have inherited a GraphQL/Apollo server and have been tasked with making several changes, one of which is adding Comments and Attachments to an existing Card object type (something similar to Trello). For the purposes of keeping this question simple I will only refer to Comments, assuming that the solution can also be applied to Attachments, which are suffering the same issue.
I have Mutations to Create, Update and Delete Comments, as well as the Repository, Resolver and have defined them in files below. The schema is also below for reference.
The problem being encountered is that the deleteComment mutation is failing to find the Comment to be deleted, returning a GraphQL error Could not find any entity of type "Comment" matching:. I have been able to positively confirm that the correct ID is traced through the entire path to the SQL query. However, the updateComment mutation, which uses the same access method to find the Comment, does successfully find and update the body of the correct Comment. I have been able to produce these results in both my developed frontend, and the Apollo Sandbox.
The only solution I have tried has been to define queries for Comments (both front and back end). This didn't appear to make any difference to the end result.
deleteComment.graphql
mutation DeleteComment($id: String!) {
deleteComment(id: $id) {
id
}
}
Comment.repository.ts
import { EntityRepository } from 'typeorm';
import { FindOneOptions } from 'typeorm/find-options/FindOneOptions';
import { BaseRepository } from './Base.repository';
import { Comment } from '../entities';
#EntityRepository(Comment)
export class CommentRepository extends BaseRepository<Comment> {
/**
* Fetch a comment using its UUID
* #param {string} id - UUID for comment being fetched
* #param {FindOneOptions<Comment>} options - Optional TypeORM find options
* #throws {EntityNotFoundError} if no entities match given UUID
* #returns {Promise<Comment>} Comment entity
*/
findById(id: string, options?: FindOneOptions<Comment>) {
return this.findOneByIdOrThrow(id, { ...options });
}
}
CommentResolver.ts
import { Arg, Mutation, Resolver } from 'type-graphql';
import { getConnection } from 'typeorm';
import { Comment } from '../models/entities';
import { CommentCreatePayload, CommentUpdatePayload } from '../graphql/types/CommentPayload';
import { CommentRepository } from '../models/repositories';
#Resolver()
export class CommentResolver {
private commentRepository: CommentRepository =
getConnection().getCustomRepository(CommentRepository);
#Mutation(() => Comment)
async createComment(
#Arg('commentCreatePayload', () => CommentCreatePayload) data: CommentCreatePayload,
) {
return this.commentRepository.insertWithValidate(data);
}
#Mutation(() => Comment)
async updateComment(
#Arg('id', () => String) id: string,
#Arg('commentUpdatePayload', () => CommentUpdatePayload) patch: CommentUpdatePayload,
): Promise<Comment> {
return this.commentRepository.updateWithValidate(id, patch);
}
#Mutation(() => Comment)
async deleteComment(
#Arg('id', () => String) id: string): Promise<Comment> {
return this.commentRepository.deleteOrThrow(id);
}
}
Comment.entity.ts
import { Entity, Column, ManyToOne } from 'typeorm';
import { ObjectType, Field } from 'type-graphql';
import { Base, Card, User } from './index';
#ObjectType()
#Entity()
export class Comment extends Base {
#Field(() => String)
#Column('text')
body: string;
#Field(() => User)
#ManyToOne(() => User, (user) => user.comments, { onDelete: 'CASCADE' })
user: User | undefined;
#Field(() => String)
#Column('text')
userId: string;
#Field(() => Card)
#ManyToOne(() => Card, (card) => card.comments, { onDelete: 'CASCADE' })
card: Card | undefined;
#Field(() => String)
#Column('text')
cardId: string;
}
schema.graphql (some parts omitted)
type Query {
list(id: String!): List!
card(id: String!): Card!
cardByShortId(shortId: String!): Card!
boards(archived: Boolean = false): [Board!]!
board(id: String!): Board!
boardByShortId(shortId: String!): Board!
archivedSwimlanes(boardId: String!): [Swimlane!]!
archivedLists(boardId: String!): [List!]!
currentUser: User!
swimlane(id: String!): Swimlane!
label(id: String!): Label!
}
type Card {
id: String!
createdAt: DateTime!
updatedAt: DateTime!
deletedAt: DateTime
version: Float!
shortId: String!
name: String!
slug: String!
rank: String!
description: String
startTime: DateTime
endTime: DateTime
ownerId: String!
listSection: ListSection!
listSectionId: String!
comments: [Comment!]!
attachments: [Attachment!]!
labels: [Label!]!
labelIds: [String!]!
users: [User!]!
userIds: [String!]!
}
type Comment {
id: String!
createdAt: DateTime!
updatedAt: DateTime!
deletedAt: DateTime
version: Float!
body: String!
user: User!
userId: String!
card: Card!
cardId: String!
}
type Mutation {
createCard(cardCreatePayload: CardCreatePayload!): Card!
updateCard(cardUpdatePayload: CardUpdatePayload!, id: String!): Card!
addLabelToCard(labelId: String!, id: String!): Card!
removeLabelFromCard(labelId: String!, id: String!): Card!
archiveCard(id: String!): Card!
recoverCard(id: String!): Card!
deleteCard(id: String!): Card!
createComment(commentCreatePayload: CommentCreatePayload!): Comment!
updateComment(commentUpdatePayload: CommentUpdatePayload!, id: String!): Comment!
deleteComment(id: String!): Comment!
}
input CommentCreatePayload {
id: String
body: String
userId: String!
cardId: String!
}
input CommentUpdatePayload {
body: String
}

"Variable '$data' expected value of type 'VoteCreateInput"

When I am trying to do the "vote" mutation, getting the below error. My other mutations are working fine.
When I am trying to do the "vote" mutation, getting the below error. My other mutations are working fine.
When I am trying to do the "vote" mutation, getting the below error. My other mutations are working fine.
"data": null,
"errors": [
{
"message": "Variable '$data' expected value of type 'VoteCreateInput!' but
got: {\"user\":{\"connect\":
{\"id\":\"ck1j3nzi68oef090830r8wd6b\"}},\"link\":{\"connect\":
{\"id\":\"ck1j58loj8x570908njwe4eu7\"}}}. Reason: 'User' Expected non-null
value, found null. (line 1, column 11):\nmutation ($data:
VoteCreateInput!) {\n ^",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"vote"
]
}
]
Mutation
async function vote(parent, args, context, info) {
// 1
const userId = getUserId(context)
// 2
const linkExists = await context.prisma.$exists.vote({
user: { id: userId },
link: { id: args.linkId },
})
if (linkExists) {
throw new Error(`Already voted for link: ${args.linkId}`)
}
// 3
return context.prisma.createVote({
user: { connect: { id: userId } },
link: { connect: { id: args.linkId } },
})
}
datamodel.schema
type Link {
id: ID! #id
createdAt: DateTime! #createdAt
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
type User {
id: ID! #id
name: String!
email: String #unique
password: String!
links: [Link!]!
votes: [Vote!]!
}
type Vote {
id: ID! #id
link: Link!
user: User!
}
schema.graphql
type Mutation {
vote(linkId: ID!): Vote!
}
type Link {
id: ID!
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
There was a glitch in prisma database which was not updating with the change in data model.
I have created a new instance of the db and now its working fine.

How resolve a custom nested extendType resolver with prisma nexus?

I need resolve a custom resolver from a prisma type. But I can't access to children in this case course or subjects, my person type only resolve data over one level.
Deps:
"nexus": "0.11.7",
"nexus-prisma": "0.3.7",
"prisma-client-lib": "1.30.0",
...
Datamodel:
type Person {
id: ID! #unique
firstName: String!
secondName: String
firstSurname: String!
secondSurname: String
sex: SexTypes
address: String
commune: Commune
region: Region
course: Course
phone: String
state: StudentStateTypes #default(value: ACTIVE)
user: User! #relation(name: "UserPerson", onDelete: CASCADE)
birthday: DateTime
registrationNumber: String
listNumber: Int
previousSchool: OtherSchool
scholarship: Scholarship
createdAt: DateTime!
updatedAt: DateTime!
}
type Course {
id: ID! #unique
client: Client
name: String!
person: [Person!]!
teacher: User
subjects: [Subject!]!
evaluations: [Evaluation!]!
createdAt: DateTime!
updatedAt: DateTime!
}
type Subject {
id: ID! #unique
client: Client
name: String!
date: DateTime
isEvaluable: Boolean
order: Int
course: [Course!]!
evaluations: [Evaluation!]!
createdAt: DateTime!
updatedAt: DateTime!
}
type Evaluation {
id: ID! #unique
client: Client
name: String!
date: DateTime!
period: Int!
description: String
coefficientTwo: Boolean
course: Course!
subject: Subject
qualifications: [Qualification!]! #relation(name: "EvaluationQualification", onDelete: CASCADE)
createdAt: DateTime!
updatedAt: DateTime!
}
type Qualification {
id: ID! #unique
client: Client
value: Float!
evaluation: Evaluation! #relation(name: "EvaluationQualification", onDelete: SET_NULL)
person: Person
createdAt: DateTime!
updatedAt: DateTime!
}
My resolver:
export const query = extendType({
type: 'Query',
definition (t: any) {
t.field('qualificationsCustom', {
type: 'Person',
args: {
id: idArg()
},
resolve: async (parent: any, args: any, ctx: any) => {
const person = await ctx.prisma.person({ id: args.id })
const qualifications = person && person.course.subjects.reduce((acc: any, subject: any) => {
acc.push({
subject: subject.name
})
return acc
})
console.log(qualifications)
}
})
}
})
person variable only resolve the next:
{
birthday: '2008-10-27T00:00:00.000Z',
secondName: 'Gisel',
...
And person.course is undefined :/
What I'm doing wrong?
Calling prisma.person({ id: args.id }) will only fetch the requested Person. It does not eager load any associated models. You can query the relations for a particular model instance by utilizing the fluent API as shown in the docs:
prisma.person({ id: args.id }).course()
or even:
prisma.person({ id: args.id }).course().evaluations()
You can also get everything at once by providing a fragment that specifies what fields, including relations, you want to fetch as shown here:
const fragment = `
fragment PersonWithCourse on Person {
# other person fields here
course {
# some course fields here
}
}
`
prisma.person({ id: args.id }).$fragment(fragment)

How to add item into an list field?

I want to add members to chatRoom member list by passing memberId to graphql mutation function. But it pop up some errors. I have attached most code that relevant to this question as below. Please help me to figure it out. I guess create: {connect } might be the cause of this issue.
//Here is Mutation function
async function addMemberToChatRoom(parent, args, context, info) {
const member = await context.prisma.users({
where: {
id: args.memberId
}
});
const chatRoom = await context.prisma.updateChatRoom({
where: {
id: args.roomId
},
data: {
users: {
create: {
{ connect: { id: args.memberId } }
}
}
}
})
return chatRoom
}
//Here is prisma datamodel
type User {
id: ID! #id
name: String!
email: String! #unique
password: String!
}
type ChatRoom {
id: ID! #id
name: String!
users: [User]!
}
type Message {
id: ID! #id
content: String!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
}
//Here is Schema.graphql
type Query {
info: String!
users: [User!]!
}
type Mutation {
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
createChatRoom(name: String!): ChatRoom
addMemberToChatRoom(roomId: String!, memberId: String!): ChatRoom
}
type AuthPayload {
token: String!
user: User!
}
type User {
id: ID!
name: String!
email: String!
}
type ChatRoom {
id: ID!
name: String!
users: [User!]
}
//Here is index.js
const { GraphQLServer } = require('graphql-yoga')
const { prisma } = require('./generated/prisma-client')
const Query = require('./resolvers/Query')
const Mutation = require('./resolvers/Mutation')
// const User = require('./resolvers/User')
const resolvers = {
Query,
Mutation
}
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: request => {
return {
...request,
prisma,
}
},
tracing: true,
})
server.start(() => console.log(`Server is running on http://localhost:4000`))
//Here is error
{
"data": {
"addMemberToChatRoom": null
},
"errors": [
{
"message": "Variable '$data' expected value of type 'ChatRoomUpdateInput!' but got: {\"users\":{\"create\":{\"id\":\"cjuzcf7lx75g60b953w50uwdc\"}}}. Reason: 'users.create[0].name' Expected non-null value, found null. (line 1, column 46):\nmutation ($where: ChatRoomWhereUniqueInput!, $data: ChatRoomUpdateInput!) {\n ^",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"addMemberToChatRoom"
]
}
]
}
I remove create and change it to
users:
{
connect: { id: args.memberId }
}
then it works.
async function addMemberToChatRoom(parent, args, context, info) {
const member = await context.prisma.users({
where: {
id: args.memberId
}
});
const chatRoom = await context.prisma.updateChatRoom({
where: {
id: args.roomId
},
data: {
users: {
connect: { id: args.memberId }
}
}
})
const returnedChatRoom = await context.prisma.chatRooms({
where: {
id: args.roomId
}
});
return returnedChatRoom
}

graphql required fields approach

This is my graphql schema, query and mutations.
I marked required fields in my schema with "!"
How I can create mutation to add new client?
Do I really need to write the same required fields again?
Like createClient(contactMethod: String!, hearAbout: String! ......... ): Client
const typeShard = `
type ClientProfile {
name: String!
surname: String!
address: String
language: String!
}
type Client {
_id: String
isEdit: Boolean
createdAt: String
shortId: Int
profile: ClientProfile
comments: String
contactMethod: String!
hearAbout: String!
leadAgentId: String
branchId: String!
}
`;
const queryShard = `
getAllClients: [Client]
`;
const mutationShard = `
removeClient(shortId : Int!): Client
createClient(contactMethod: String!, hearAbout: String! ......... ): Client
`;
const resolvers = {
Query: {
getAllClients: () => MongoClients.find().fetch(),
},
Mutation: {
removeClient(root, { shortId }) {
const client = MongoClients.findOne({ shortId });
if (!client) throw new Error(`Couldn't find client with id ${shortId}`);
MongoClients.remove({ shortId });
return client;
},
createClient: (_, args) => {
return MongoClients.insert(args);
},
},
};
You do not need to write the same fields for every mutation. You could define an input type. Please take a look at this cheat sheet.
So in your case it could look like:
const typeShard = `
type ClientProfile {
name: String!
surname: String!
address: String
language: String!
}
type Client {
_id: String
isEdit: Boolean
createdAt: String
shortId: Int
profile: ClientProfile
comments: String
contactMethod: String!
hearAbout: String!
leadAgentId: String
branchId: String!
}
input ClientInput {
contactMethod: String!
hearAbout: String!
.....
}
`;
const mutationShard = `
removeClient(shortId : Int!): Client
createClient(clientInput: ClientInput!): Client
`;

Resources