1. What are the trade-offs of using GraphQL in a frontend?
Discuss GraphQL as a browser-facing API choice and explain which trade-offs have influenced technical decisions in your own frontend work.
I use GraphQL when the UI needs flexible data shapes and I want to reduce over-fetching. A user action builds a GraphQL query and variables, then the browser sends one HTTPS request directly to the external GraphQL API. I keep AbortController separate so an obsolete request can be canceled, and I ignore stale responses before they update the screen. When JSON returns, I check the HTTP result, content type, parsing, and GraphQL response shape. I keep loading, success, empty, aborted, and error states separate. CORS protects the browser boundary, while the trusted server still owns authorization. In my frontend decisions, I choose GraphQL when flexible data needs outweigh extra client complexity and weaker default HTTP caching.
GraphQL lets a frontend ask for the data shape one screen needs. This can reduce over-fetching and some extra requests. The trade-off is more work in the browser application. Queries can become complex. Client caching and partial errors also need careful handling. In this design, a user action builds a GraphQL request and sends it directly to one external API boundary. AbortController can cancel obsolete work without becoming a network hop. The browser validates the returned JSON before changing UI state. In my frontend decisions, I use these trade-offs to decide whether GraphQL is worth the added complexity.
- What GraphQL query and response shapes must the frontend support?
- How does the browser receive authentication state: cookies or tokens?
- What caching behavior does the API support?
- Should obsolete requests be canceled, ignored when stale, or both?
- Are partial GraphQL responses with both data and errors expected?
- Are persisted queries available or required?
A user action or page event starts the flow. The frontend first validates its input. It then builds the GraphQL query and variables.
The diagram shows this example query:
query GetUser($id: ID!) { user(id: $id) { id name email } }
The frontend may add supported headers and authentication state. The exact HTTP method is not defined by this design. The browser sends an HTTPS GraphQL request directly to the external GraphQL API. The diagram shows /graphql only as an example endpoint shape.
The API returns JSON containing GraphQL data, errors, or both. This matters because GraphQL can return useful data together with field-level errors. The frontend therefore should not treat every response as only success or failure.
When the request starts, the UI can enter a loading state. Request creation and cancellation remain separate responsibilities.
AbortController does not sit between the frontend and API. It controls the browser's in-flight request. If a newer request makes an older one unnecessary, the frontend can send an abort signal. The frontend can also ignore an out-of-date response before it changes UI state.
The HTTPS request still flows directly from request construction to the GraphQL API. This matches the main request path in the diagram.
When an HTTP response arrives, Fetch normally resolves even when the HTTP result represents an error. The frontend must inspect the response before trusting the expected body.
First, it checks the HTTP result. Next, it checks the Content-Type. Then it parses the JSON. After parsing, it validates the GraphQL response shape before changing application state.
The response can contain data, errors, or both. Runtime shape checking protects the UI from unexpected network data. Only validated data should move into the normal UI update path.
After validation, the frontend updates its local state. It may also normalize or cache validated data in its client-side cache.
The visible UI states stay separate. The diagram shows loading, success, empty, aborted or stale, and error states. The error path can include validation, authentication, authorization, retryable, or final errors when those conditions are known by the surrounding contract.
An aborted request should not appear as an ordinary application failure. A stale response should be ignored instead of replacing newer data.
GraphQL also needs a clear partial-error rule. A response can contain both data and errors. The frontend must decide whether the available data is safe and useful to display.
CORS is a browser mechanism that controls whether frontend JavaScript can read allowed cross-origin responses. It is not authentication. The same-origin policy also restricts cross-origin access in the browser.
Credentials must follow the application's security policy. Cookies or tokens may carry authentication state. When cookies are sent automatically, CSRF protection can matter. The diagram shows SameSite cookies or CSRF tokens as possible protections.
An HttpOnly cookie cannot be read by JavaScript. The diagram also allows token state to be kept in memory when that matches the authentication design.
GraphQL schema visibility does not grant permission to access data. The trusted server must still enforce authorization. Persisted queries can reduce some query-related risk, but they do not replace authorization.
The main benefit is precise data selection. A screen can request the fields it needs. This reduces many over-fetching problems.
A single GraphQL API surface can also simplify the frontend request model. However, it can concentrate the client's dependency on that API surface. Actual availability still depends on backend redundancy.
The first major cost is complexity. Queries can grow large or deeply nested. The frontend also needs query management, schema discipline, validation, and team learning.
Caching is another trade-off. GraphQL does not automatically map each data shape to a separate HTTP resource. Normal HTTP and CDN caching can therefore be less direct. A normalized client cache can help, but it adds another layer of state management.
Performance still depends on query shape. Asking for exact fields can reduce unnecessary data, but a large query can still be expensive. Partial errors also require clear UI behavior.
In my frontend decisions, I use a simple rule. I choose GraphQL when flexible UI data shapes and reduced over-fetching are more valuable than added client complexity and weaker default HTTP caching.
Interviewers use this question to test engineering judgment, not GraphQL syntax. They want to see whether you understand the browser-to-API boundary, request and response validation, cancellation, stale responses, UI state, caching, and security ownership. They also want you to separate authentication from authorization and explain CORS correctly. A strong answer shows that you can choose GraphQL for the right frontend needs while clearly explaining its complexity, reliability, caching, performance, and maintenance trade-offs.






