Backend
Overview
The application connects to multiple services – DatoCMS, Recruitee, HubSpot, IPStack – all of which are abstracted away under a GraphQL API Gateway, available as an API Route at /api/graphql
. Whenever we refer to "backend" in this documentation, we are talking about this GraphQL API.
Consumption points ⏩
The GraphQL layer behind the API Route is executed under three (3) different scenarios. To explain these scenarios, we'll use the Blog domain as an example.
1. Server-side rendering
When, for example, the main blog page (/blog
) is accessed from a direct link (no client-side navigation), the whole page is rendered on the server-side. During this process, the GraphQL layer is made available to the rendering bundle, and is consumed directly using a local link – aka, Schema Link. This ensures that:
- No
/api/graphql
HTTP requests are made - GraphQL server is initiated only once (it's heavy)
- Only external services HTTP requests are executed
In case of the /blog
page example, there are two queries executed sequentially:
- Featured and trending posts
- Latest posts, excluding the items found on the above lists
As you can see, 2 HTTP requests are performed, but both are executed on the server-side on the same render cycle. The response of the /blog
HTTP request is a rendered HTML, containing the data resolved by both these GraphQL operations.
2. Client-side navigation
When a user reaches the blog page comming from another page on the website, it enters Next.js client-side navigation flow. Besides the common fetching of JS bundles related to the new page, Next.js also triggers a request to a special endpoint, which serves the output of the getServerSidePage
. This specific execution environment behaves exactly the same as the Server-side rendering process explained above.
Next.js abstracts alway all the data handling and mapping to components as properties.
3. Client-side only requests
There are multiple scenarios where the GraphQL API might be requested from the client-side, that wouldn't be cover by items 1 & 2 above. A good example is pagination on the /blog
page:
When you hit "Load more" to get more posts, the same query is used to perform the request – only with different parameters. This ensures that Apollo understands the data as being part of the previously available query and data, and merges the result accordingly.
In terms of execution, this is the simplest of the 3 scenarios explained here. One might be tempted to think that having such query executed from client-side could pose a security or performance risk to the backend, but keep in mind these requests are limited to the ones known to the application, using a technique called Persisted Queries, resulting in the server only responding to allowed queries, predefined queries. Furthermore, these queries results are heavily cached (read Performance), and thus a second user that hit "Load more" on the blog page, will get a previous user's result cached on the CDN.
Performance ⚡
As of any Next.js API Route, the whole backend implementation is stateless, and is booted and executed for each API request. However, every single direct request is heavily cached on CDN (with the exception of Mutations). This not only ensures we are not easily prone to load attacks, but guarantees a fast as possible response time for consumption queries.
All of the scenarios mentioned on the Consumption points above are prone to the same caching system. Meaning:
- Server-side rendering: caches the whole HTML output.
- Client-side navigation: caches result of the fetching
getServerSideProps
data. - Client-side only requests: caches result of GraphQL operation executed.
Security 🛡️
The secret environment variables that allow access to the multiple connected services are never exposed to the client-side. In fact, with the GraphQL Gateway on the way, there is virtually no need to expose variables to the client-side. If you check the ../config/env.js file, you'll notice that all of the publicly accessible variables (the ones prefixed with NEXT_PUBLIC_
) are analytic or build related.
This ensures that there is never gonna be a misuse of the services hidden behing the GraphQL Gateway. Although all data from DatoCMS could be public, for instance, inadvertent or malicious direct use of these external APIs could increase the costs of usage of such services.