GraphQL is expected to expose a single endpoint to query the data. However, there are situations where it makes sense to instead expose multiple custom endpoints, where each of these endpoints presents a customized schema. This allows us to provide a distinct behavior for different users or applications by simply swapping the accessed endpoint.
Exposing multiple endpoints in GraphQL does not equate to REST. While in REST every endpoint provides access to a predefined resource or set of resources, each of the multiple GraphQL endpoints will still provide access to the whole data from its schema, enabling to fetch exactly what we need. So this is still the normal GraphQL behavior, with the addition of being able to access the data from different schemas.
This capability is also different than schema stitching or federation, which enable to incorporate several sources of data into a single, unified graph. With multiple endpoints we are dealing with multiple schemas. It is the intention to deal with them on their own, and not as part of a bigger schema.
A good example of this might be if you've company is centered around a product and has built a graphql API for that product, and then decides to expand into a new business domain with a new product that doesn't relate to the original product. It could be a burden for both of these unrelated products to share a single API and two separate endpoints with different schema may be more appropriate.
[...] Another example is [...] - you may have a separate internal-only endpoint that is a superset of your external GraphQL API. Facebook uses this pattern and has two endpoints, one internal and one external. The internal one includes internal tools which can interact with product types.
Let's explore some additional use cases when exposing multiple GraphQL endpoints makes sense.
Exposing the admin and public endpoints separately permalink
When we are using a single graph for all data in the company, we can validate who has access to the different fields in our GraphQL schema by setting-up access control policies. For instance, we can configure fields to be accessible only to logged-in users or users with a certain role.
However, when there are fields which contains sensitive or confidential information, so that under no circumstance these should be accessible to unintended actors, then we'd rather not expose these fields in a public schema in first place, and only in a private schema that only the team has access to. This strategy will protect our private data from unintended issues, such as software bugs and carelessness when configuring the schema, and even tighten security by only allowing visitors from certain IPs to access the private endpoint.
Hence, we can create two separate schemas, the Admin and Public schemas, and expose them under endpoints /graphql/admin (and restrict access to it to visitors from a certain IP) and /graphql/public (accessible to everyone) respectively.
Restricting access to private information in a safer way permalink
This section is a generalization of the previous one: it's not just public vs admin, but any situation in which a set of users must certainly not be able to access information from another set of users.
For instance, whenever we need to create customized schemas for our different clients, we can expose a custom endpoint for each of them (/graphql/some-client, /graphql/another-client, etc), which can be safer than giving them access to the same unified schema and validating them via access control.
Providing a different behavior to different applications permalink
We can grant a different behavior to the different applications accessing the same data source.
For instance, Reddit produces a dissimilar response if accessed from a desktop browser or from a mobile browser. From the desktop browser, whether we are logged-in or not, we can directly visualize the content:
Accessing from mobile, though, we must be logged-in to access the content, and we're encouraged to use the app instead:
This different behavior could be provided by creating two schemas, the Desktop and Mobile schemas, and expose them under /graphql/desktop and /graphql/mobile respectively.
Generating a site in different languages permalink
If we want to generate the same site in different languages, we can have the language code already be part of the custom endpoint structure, such as /graphql/en for English and /graphql/fr for French. Then, the GraphQL server can retrieve this information and translate the data to the desired language.
Finally, we point to each of these endpoints in the static site generator to produce the site in one or another language:
Testing an upgraded schema before releasing for production permalink
If we want to upgrade our GraphQL schema, and have a set of users test it in advance, we can expose this new schema via a /graphql/upcoming endpoint. Even more, we could also expose a /graphql/bleeding-edge endpoint, that keeps deploying the schema from DEV.
In this model, a custom BfF is the middleman between the back-end services and its client:
This model can be satisfied in GraphQL by having all BfFs be implemented in a single GraphQL server with multiple endpoints, with each endpoint tackling a specific BfF/client (such as /graphql/mobile and /graphql/web):