Skip to main content

Data Fetching In EverShop

Data Fetching in EverShop

EverShop uses GraphQL for data fetching. GraphQL is a query language for your API and a server-side runtime for executing queries using a type system you define for your data.

info

Check this GraphQL document to learn more about GraphQL in EverShop.

EverShop allows you to fetch data for your React components using the GraphQL query language. This document explains how to fetch data from the server using GraphQL.

GraphQL Query in React Components

When creating a React component that requires data for SSR (Server-Side Rendering), you need to fetch the data from the server during the request time. To do this, export a GraphQL query in the React component file. The query will be executed on the server, and the result will be passed to the React component as a prop.

Let's look at the example below:

modules/catalog/pages/productView/GeneralInformation.jsx
export default function GeneralInfo({ product }) {
return (
<Area
id="productViewGeneralInfo"
coreComponents={[
{
component: { default: Name },
props: {
name: product.name,
},
sortOrder: 10,
id: "productSingleName",
},
{
component: { default: Price },
props: {
regular: product.price.regular,
special: product.price.special,
},
sortOrder: 10,
id: "productSinglePrice",
},
{
component: { default: Sku },
props: {
sku: product.sku,
},
sortOrder: 20,
id: "productSingleSku",
},
]}
/>
);
}


export const query = `
query Query {
product (id: getContextValue('productId')) {
name
sku
price {
regular {
value
text
}
special {
value
text
}
}
}
}`;

In the example above, we export a GraphQL query in the GeneralInformation.js component file. During the request time, EverShop consolidates all queries from all components and executes them in a single request. The result of the GraphQL query is passed to the React component as a prop.

When is the GraphQL Query Executed?

The query is executed on the server during the request time. It will only be executed if the component is rendered on the server.

The GraphQL query is extracted from the component file and executed on the server. The result of the query is then passed to the component as a prop.

The GraphQL Query Format

warning

Since the build process uses Regex to parse, collect, and remove queries from the component file, you must ensure the export statement follows the format below:

export const query = `<Your GraphQL query>`;

The getContextValue Function

Sometimes, you need to pass arguments to the GraphQL query. For example, to fetch product details for a specific product, you need to pass the product ID to the GraphQL query. To do this, use the getContextValue function. This function returns the value of the context key you pass to it.

modules/catalog/pages/productView/GeneralInformation.jsx
export const query = `
query Query {
product (id: getContextValue('productId')) {
name
sku
price {
regular {
value
text
}
special {
value
text
}
}
}
}`;

To add a value to the context, use a middleware function. Here's an example:

modules/catalog/pages/categoryView/index.js
import { select } from "@evershop/postgres-query-builder";
import { pool } from "@evershop/evershop/lib/postgres";
import { setContextValue } from "@evershop/evershop/graphql/services";

export default async (request, response, next) => {
try {
const query = select();
query
.from("category")
.leftJoin("category_description")
.on(
"category.`category_id`",
"=",
"category_description.`category_description_category_id`"
);

query.where("category_description.`url_key`", "=", request.params.url_key);
const category = await query.load(pool);

if (category === null) {
response.status(404);
next();
} else {
setContextValue(request, "categoryId", category.category_id);
setContextValue(request, "pageInfo", {
title: category.meta_title || category.name,
description: category.meta_description || category.short_description,
url: request.url,
});
next();
}
} catch (e) {
next(e);
}
};

In the example above, the middleware function index.js validates the category's availability. If the category is available, we add the category ID to the context using the setContextValue function. The getContextValue function then retrieves the category ID from the context.

The setContextValue Function

This function adds a value to the GraphQL execution context. It accepts three arguments:

  • request: The request object.
  • key: The context key.
  • value: The context value.
info

By default, EverShop adds all data in the current request object to the context. For example, you can call the getContextValue('url') function to get the current request URL.

How Server-Side Data Fetching Works Internally

Understanding the internal mechanism helps you debug data-fetching issues and write more effective queries.

Build Time: Query Extraction

During the build process, EverShop scans all React components for each route and:

  1. Extracts the export const query from each component file using regex.
  2. Aliases all selected fields to prevent naming collisions across components (e.g., product.name becomes e_uniqueId_name).
  3. Encodes getContextValue() calls as Base64 placeholders.
  4. Merges all component queries into a single GraphQL query per route.
  5. Generates a propsMap that maps aliased field names back to the original component prop names.

The merged query and propsMap are saved as build artifacts.

Request Time: Query Execution

When a request arrives for a page route:

  1. The buildQuery middleware reads the pre-built query file.
  2. It decodes getContextValue() placeholders by replacing them with actual values from the request context (set by earlier middleware).
  3. If any widgets are registered for the route, their queries are merged in as well.
  4. The graphql middleware executes the merged query against the schema.
  5. The response middleware uses the propsMap to distribute the query results back to each component as props.
  6. React's renderToString() produces the HTML with all data pre-filled.

This is why setContextValue() must be called in a middleware that runs before the GraphQL query execution — the values need to be available when placeholders are replaced.

Client-Side Data Fetching

GraphQL API Endpoint

EverShop provides a GraphQL API endpoint to fetch data from the server. The GraphQL API endpoint is available at the /graphql path. You can use this endpoint to fetch data from the server.

The useQuery Hook from URQL

EverShop uses URQL to fetch data from the server using the GraphQL API. URQL is a fully-featured GraphQL client that supports all GraphQL features and can be used with any GraphQL server.

Example:

import React from "react";
import { useQuery } from "urql";

const TodosQuery = `
query {
todos {
id
title
}
}
`;

const Todos = () => {
const [result, reexecuteQuery] = useQuery({
query: TodosQuery,
});

const { data, fetching, error } = result;

if (fetching) return <p>Loading...</p>;
if (error) return <p>Oh no... {error.message}</p>;

return (
<ul>
{data.todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};


Support us


EverShop is an open-source project that relies on community support. If you find our project useful, please consider sponsoring us.