GraphQL: Many small mutations, or one bulk mutation?
Asked Answered
E

2

5

Let's say I am a user and I am editing my profile on some arbitrary app. The app let's me make a bunch of changes, and when I'm done, I click on "Save" and my profile gets updated.

What is the recommended best practice in GraphQL to handle a large update like this? As I see it, there are a few options:

A) Many small mutations. If the user changed 5 things (i.e., name, email, username, image, bio) the client could fire off 5 mutations to the server.

Pros: smaller, more isolated operations.

Cons: Doesn't this defeat the purpose of "one round trip to the server" in GraphQL, as it would require... 5?

B) Many small mutations, called server-side. Rather than calling 5 mutations from the client, requiring 5 round trips, you could post a data blob to the server and have a function that parses it, and runs individual mutations on the data it finds.

Pros: One round trip

Cons: We have to add another layer to the app to handle this. The new function would get messy, be hard to test, and hard to maintain over time.

C) One large mutation. The user sends the data blob to the server via a single mutation, which sets the new data in bulk on the document rather than running individual mutations on each field.

Pros: DX; one round trip.

Cons: Since fields are being passed in as arguments, this open the application to attack. A malicious user could try passing in arbitrary fields, setting fields that shouldn't be changed (i.e. an isAdmin field), etc. The mutation would have to be smart to know which fields are allowed to be updated, and reject / ignore the rest.


I can't find much on the web about which way is the "right way" to do this kind of thing in GraphQL. Hoping to find some answers / feedback here. Thanks!

Euphony answered 27/5, 2017 at 6:5 Comment(2)
One round trip to the server is really for queries, not mutations.Plosive
I think you're overthinking it. The ways 1 and 3 are both correct ways to solve this problem depending on what you need. I would go with 3 it is probably the most robust way in most cases.Redemption
C
6

A) Many small mutations. If the user changed 5 things (i.e., name, email, username, image, bio) the client could fire off 5 mutations to the server.

You can execute multiple mutations in a single request. No need to call the server multiple times.

Here's an example:

mutation {
  setUserName(name: "new_name") { ok }
  setUserEmail(email: "new_email") { ok }
}

B) Many small mutations, called server-side. Rather than calling 5 mutations from the client, requiring 5 round trips, you could post a data blob to the server and have a function that parses it, and runs individual mutations on the data it finds.

This is exactly what GraphQL does for you when you mutate multiple fields or execute multiple queries at once.

C) One large mutation. The user sends the data blob to the server via a single mutation, which sets the new data in bulk on the document rather than running individual mutations on each field.

You can still set data in bulk even if you are using multiple fields.
This would require you to, instead of updating the database directly, pass the request to a middle-ware that would build and execute a single query once all mutation resolvers are executed.

Cons: Since fields are being passed in as arguments, this open the application to attack. A malicious user could try passing in arbitrary fields, setting fields that shouldn't be changed (i.e. an isAdmin field), etc. The mutation would have to be smart to know which fields are allowed to be updated, and reject / ignore the rest.

You shouldn't use arbitrary variables, but instead list all allowed properties as arguments.

Coronet answered 29/5, 2018 at 20:44 Comment(0)
P
1

I'd go with the third solution, one large mutation. I'm not sure I understand your point about malicious users passing arbitrary fields : they wouldn't be able to pass fields that are not defined in your schema.

As for the server side logic, you'd have to put those smart checks anyway : you can never trust the client!

Petrochemical answered 28/5, 2017 at 12:1 Comment(1)
Thank you! I was definitely overthinking the security aspect of it. I hadn't realized that you can't pass in arbitrary values to a mutation to try and trick it, you can only supply the exact fields specified in your schema and they MUST be of expected type. So that means the more work you can get out of a single mutation, the better. So larger, more generic mutations it is!Euphony

© 2022 - 2024 — McMap. All rights reserved.