Not sure about the schema evolution part. Protobufs seem to work great for that.
Not sure about the schema evolution part. Protobufs seem to work great for that.
I agree with that, and when I'm in a "typescript only" ecosystem, I've switched to primarily using tRPC vs. GraphQL.
Still, I think people tend to underestimate the value of having such clear contracts and guarantees that GraphQL enforces (not to mention it's whole ecosystem of tools), completely outside of any code you have to write. Yes, you can do your own zod validation, but in a large team as an API evolves and people come and go, having hard, unbreakable lines in the sand (vs. something you have to roll your own, or which is done by convention) is important IMO.
If you just slap in Zod, the server will drop the extra inputs. If you hate Zod, it's not hard to design a similar thing.
> or if client and server disagree that a field is optional or not
Doesn't GQL have the concept of required vs optional fields too? IIUC it's the same problem. You just have to be very diligent about this, not really a way around it. Protobufs went as far as to remove 'required' out of the spec because this was such a common problem. Just don't make things required, ever :-)
Yea, graphql is what I'm referring to.
It is an important security benefit, because one common attack vector is to see if you can trick a server method into returning additional privileged data (like detailed error responses).
Therefore requests between GQL and downstream services are travelling "over the wire" (though I don't see it as an issue)
Having REST apis that return only "fat" objects is really not the most secure way of designing APIs
Because if so that is no security benefit at all, because I can just... request the fat fields.
In many REST frameworks, while you define the return object type that is sent back over the wire, by default, if the actual object you return has additional fields on it (even if they are found nowhere in the return type spec), those fields will still get serialized back to the client. A common attack vector is to try to get an API endpoint to return an object with, for example, extra error data, which can be very helpful to the attacker (e.g. things like stack traces). I'd have to search for them, but some major breaches occurred this way. Yes, many REST frameworks allow you to specify things like validators (the original comment mentioned zod), but these validators are usually optional and not always directly tied to the tools used to define the return type schema in the first place.
So with GraphQL, I'm not talking about access controls on GraphQL-defined fields - that's another topic. But I'm saying that if your resolver method (accidentally or not) returns an object that either doesn't conform to the return type schema, or it has extra fields not defined in the schema (which is not uncommon), GraphQL guarantees those values won't be returned to the client.
But you're right, if you have version skew and the client is expecting something else then it's not much help.
You could do it client-side so that if the server adds an optional field the client would immediately prune it off. If it removes a field, it could fill it with a default. At a certain point too much skew will still break something, but that's probably what you want anyway.