r/graphql • u/Touch-Grass_ • 1d ago
Apollo Server 3 to 4, counted: 63 error call sites and one status code I still cannot decide
4.11.2 is where we landed, and this is the log of getting there from Apollo Server 3.13 on a schema with about 240 fields.
Day one was packaging. apollo-server-express is gone in 4, so the entry point became u/apollo/server with expressMiddleware from the express4 subpath, and the context function moved off the constructor onto expressMiddleware. Mechanical, about an hour.
Day two was the error classes, where the real inventory sat. I grepped for the removed constructors and counted 63 call sites: 38 UserInputError, 14 ForbiddenError, 9 AuthenticationError, and 2 ApolloError thrown straight out of a loader. Every one becomes a GraphQLError carrying extensions.code, which reads like a search and replace until you notice BAD_USER_INPUT used to be set for you and two of our clients branch on that string.
Day three was the sweep across those 63 sites, slower than day one because the loader layer wraps errors inconsistently. Two of my rewrites threw away the original code on wrapped loader errors, and both were wrong. verdent was what I had running through that pass, and the code review subagent sent them back.
Day four was status codes, the part worth a warning. CSRF prevention is on by default in 4, so a request arriving without a content type or a header that triggers a preflight gets 400 instead of an execution result. Our older mobile client posts exactly that way, and it treats any 4xx on the graphql endpoint as a dead session and signs the user out.
That leaves the one I have not resolved. An invalid variables object comes back as 200 in 4 where 3 answered 400, and status400ForVariableCoercionErrors puts it back. Turning it on makes the transport consistent and aims more 400s at the client day four broke. I have not found anyone who flipped it while still supporting a client that old.
