Integrating an external pricing engine
Many enterprises have an existing pricing system (ERP, CPQ, or custom engine)
that needs to feed prices into the storefront. Evolve’s federated GraphQL
architecture lets you add an external price source as a subgraph that extends
the ProductVariant type without modifying any existing service.
-
Create a pricing subgraph
Scaffold a new service following the service creation guide. The module extends
ProductVariantwith an external price field:import { AbstractModule } from "@evolve-framework/core";import { gql } from "graphql-tag";export class ExternalPricingModule extends AbstractModule {typedefs = gql`extend type ProductVariant @key(fields: "sku") {sku: String! @externalexternalPrice: Money @shareable}type Money {centAmount: Int!currencyCode: String!}`;resolvers = {ProductVariant: {__resolveReference: resolveVariantPrice,externalPrice: externalPriceResolver,},};}The
@key(fields: "sku")and@externaldirectives are Apollo Federation directives that tell the gateway how to resolveProductVariantacross subgraphs. -
Batch with a DataLoader
External pricing APIs are often latency-sensitive. Use a DataLoader to batch multiple SKU lookups into a single API call:
import DataLoader from "dataloader";const createPriceLoader = (currency: string) =>new DataLoader<string, Money | null>(async (skus) => {const prices = await fetchPricesFromEngine(skus, currency);return skus.map((sku) => prices.get(sku) ?? null);});Create the DataLoader per request in
context.tsso each request gets its own batch window:src/context.ts import {readStoreContextFromRequest,type ServerContext,} from "@evolve-framework/core/service/graphql";import type { YogaInitialContext } from "graphql-yoga";export const createContext = async (serverContext: ServerContext & YogaInitialContext,) => {const storeContext = readStoreContextFromRequest(serverContext.request);return {...serverContext,storeContext,priceLoader: createPriceLoader(storeContext.currency),};}; -
Implement the resolver
The resolver uses the DataLoader to look up the price for each variant:
const externalPriceResolver = async (variant, _args, context) => {return context.priceLoader.load(variant.sku);}; -
Add caching
For prices that do not change every second, wrap the fetch call with the framework cache:
import { cache } from "@evolve-framework/core/cache";const fetchPricesFromEngine = async (skus, currency) => {return cache.wrapFn({key: `ext-prices:${currency}:${skus.join(",")}`,fn: () => pricingApi.getPrices(skus, currency),ttl: 300, // seconds});}; -
Compose into the supergraph
For local development, add the pricing service to the composition task in
backend/services/graphql-gateway/Taskfile.yamland recompose the local supergraph:Terminal window task -d backend/services/graphql-gateway supergraphIn production the router polls the supergraph from the Hive CDN; the new subgraph joins it through the service’s
hive_schema_publishTerraform resource. Once composed, the supergraph schema includes theexternalPricefield on everyProductVariant.The frontend can then query external prices alongside regular product data in a single GraphQL request:
query Product($slug: String!) {product(slug: $slug) {variants {skuprice { centAmount currencyCode }externalPrice { centAmount currencyCode }}}}
Further reading
Section titled “Further reading”- Data model for the vendor-independent schema and extension patterns
- GraphQL federation for how subgraphs compose into the supergraph
- Customization for extending existing types and modules

