How Cross-Origin Resource Sharing requests affect your app’s performance
The title may lead you to think that this post is another ranting post about the downside of a “Single Page Application”. It is more about shedding some light on the performance perspective to keep in mind while designing the SPA. Especially if your SPA consumes APIs from different domain services.
If you are designing an SPA which consumes the API from the same domain of the SPA, then great. You should skip this article if your SPA only pulls from the API on the same domain.
Most SPAs involve “microservices.” They consume different endpoints of services serving by different domains within the SPA. This adds resilience, fault tolerance, and an improved user experience of our product. Multiple domain requests become inevitable until and unless we strictly adhere to the same domain app API Gateway — Microservices Pattern for our SPA.
Let’s Imagine we have a GET
API /users/report/:id
served from domain api.example.com
. Our SPA is served from spa.example.com
. The :id
means its a value that can change for every request.
Can you guess the issue with the above API design with respect to CORS (Cross-Origin Resource Sharing) and its impact on the performance of our SPA?
Here’s a brief Introduction of CORS from MDN:
CORS is all good while it’s a simple request that doesn’t trigger a CORS preflight. But most often we make requests that are not a “ simple request.”
This is due to the fact that we need to send a header that is not CORS-safelisted-request-header. An example header is Authorization, x-corelation-id
. Frequently our Content-Type
header value is application/json
. This is not an allowed value for the Content-Type
header for cors-safelisted-request-header.
If our api.example.com
server accepts content-type
of application/json
, our SPA domain spa.example.com
will first send an HTTP request by the OPTIONS
method. It is sent to the resource /users/report/12345
on the other domain api.example.com
. To determine whether the actual request is safe to send, the option is sent preflighted. Cross-site requests are always preflighted like this, since they may have implications for user data.
It’s the job of api.example.com
server to let the other domain spa.example.com
know it’s safe to send the data. You might have done something similar to this for CORS inside your Application.
Once the api.example.com
server sends the proper response from “OPTIONS” method to other domain spa.example.com
then only the actual data with the request you were trying to make is done.
So to access a resource
api.example.com/users/report/12345
two actual requests were performed.
You might say yes. We can use the Access-Control-Max-Age header
to cache the results of a preflight request. The next time we access the resource api.example.com/users/report/12345
from spa.example.com
there is no preflight request.
Yes, that’s true, but then remember the title — The terrible performance cost of CORS requests on the single-page application (SPA). This comes from the API that we’re are consuming and the way it’s been designed. In our example, we designed our API /users/report/:id
, where :id
means its a value that can change.
The way preflight cache works is per URL, not just the origin. This means that any change in the path (which includes query parameters) warrants another preflight request.
So in our case, to access resource api.example.com/users/report/12345
and api.example.com/users/report/123987
, it will trigger four requests from our SPA in total.
If you have a slow network, this could be a huge setback. Especially when an OPTIONS request takes 2 seconds to respond, and another 2 for the data.
Now imagine your SPA application making millions of such requests for different domains. It will have a terrible impact on your SPA’s performance. You’re doubling the latency of every request.
SPAs are great in their own domain. But for consuming different domains they come with their own cost. If the API is poorly designed, the latency issues of your SPA can hurt more than the benefits they provide.
There is no solution or technology that is wholly good or bad. Knowing its shortcoming and what it takes to make it work are what matters. This is what differentiates your Application from the others.
Learned something? Clap your 👏 to help others find this article.