I’ve recently built some small things using GraphQL at the API level. It’s been fun and refreshing but at the same time I feel there’s so much new things that it feels a bit overwhelming.

CORS (Cross-origin resource sharing) is an age-old pain point of web developers. It involves a lot of implicit things done by the browser and the rules feel somewhat arbitrary.

One tricky part of CORS is the preflight request. This is a separate HTTP request automatically sent by the browser to identify whether it is OK to send certain requests (basically anything intended to alter data) to the server. It uses the OPTIONS HTTP method.

The preflight request comes with a problem: it’s an extra round trip to the server that induces latency to the requests – if transportation is the bottleneck in the actual request, it can essentially double the time taken by the API call. The issue becomes very real with an API-driven web service that sends a large number of requests. While there are ways to cache or circumvent the preflight request, the methods are quite limited. This is where we GraphQL comes to rescue.

Preflight requests are typically resource-specific. This means that for each new route (API endpoint in REST) there’s a new preflight request sent despite any cache directives. This introduces the round trip delay to each POST1, PUT and DELETE on different requests or endpoints. What’s the solution? With REST, the best (or only) good solution is to move the API under the same domain. If this is not possible, you’re basically out of luck.

With GraphQL, we can avoid the trouble. If you are familiar with the GraphQL spec, you know that all queries and mutations are done using the same HTTP method (POST) and the same resource path (typically /graphql). This gives us the surprising benefit of allowing preflight responses to be cached across resources! We only have to suffer one OPTIONS request while the rest of the API call are performed without the extra round trip. To me, this was an unexpected benefit of using GraphQL.

1. This is not strictly true: a limited set of POST requests can be sent without preflight but this is rarely useful.