The Stack
First, this is a post of what I think are the disadvantages of graphql combined with Prisma and graphql-yoga.
First
For this model
type Company @db(name: "companies") {
id: ID! @id
active: Boolean! @default(value: true)
name: String!
createdBy: User! @relation(link: INLINE)
createdAt: DateTime! @createdAt
updatedAt: DateTime! @updatedAt
}
Here is how a mutation would be done.
async createCompany(parent, args, ctx, info) {
// 1. Check if they are logged in
if (!ctx.request.userId) {
throw new Error('You must be logged in!');
}
// 2. create
const company = await ctx.db.mutation.createCompany(
{
data: {
...args,
active: true,
}
},
info
);
return company;
}
Now for adding the createdBy attribute, this should be added to data
{
data: {
...args,
active: true,
// notice the connect object
createdBy: { connect: { id: ctx.request.userId } }
}
}
Adding the userId in the connect object feels a little bloated, but it is not a big deal, it is fine. This will add only the id in the document of company.
Now, what if we want to add the user as a whole subdocument?
Then the existing Company model cannot be extended and the current model of User should have the @embedded config.
type User @embedded {
name: String!
email: String! @unique
password: String!
resetToken: String
resetTokenExpiry: Float
}
And here is when it gets complicated
Now we want to use the create company mutation
{
data: {
...args,
active: true,
user: {
create: {
// here goes all the user attributes that are required
}
},
createdBy: { connect: { id: ctx.request.userId } }
}
},
This time the user object should be wrapped around a create object, and guess what happens if the user has another subdocument?
{
data: {
...args,
active: true,
user: {
create: {
// what if the user has a permissions subdocument ?
permissions: {
create: {
name: "ADMIN"
}
}
}
},
createdBy: { connect: { id: ctx.request.userId } }
}
},
Each time a subdocument is added it has to be wrapped around a create object! That's really annoying. For complex models, this will bloat the creation of documents with a lot of create objects.
And here it is another thing, for each create object, when it is saved in the database, it will create an _id attribute for each level even if it is not specified in the model, so this is unnecessary.
Second
Reusing the first mutation defined
async createCompany(parent, args, ctx, info) {
// 1. Check if they are logged in
if (!ctx.request.userId) {
throw new Error('You must be logged in!');
}
// 2. create
const company = await ctx.db.mutation.createCompany(
{
data: {
...args,
active: true,
}
},
info
);
return company;
}
When this is called from the frontend using the Apollo Client
This is how the mutation can be called
// create new company
const promise = mutate({
mutation: COMPANY_MUTATION,
variables: { name: inputValue.value }
});
promise.then((item) => {
// to access the data returned from the server.
const name = item.data.createCompany.name;
});
So, the response is filled with an object called data and another object with the name of the method defined in the server. This also feels bloated because now you have to know the method name of the backend while accessing the data in the frontend.
End
This is list is short, but I really don't like them. What do you think?
Top comments (1)
I think I would not even touch GraphQL using plain Javascript. It looks fragile