Skip to main content

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.

1. Create a pricing subgraph

Scaffold a new service following the service creation guide. The module extends ProductVariant with an external price field:

import { AbstractGraphQLModule } from "@evolve-framework/core";
import { gql } from "graphql-tag";

export class ExternalPricingModule extends AbstractGraphQLModule {
typedefs = gql`
extend type ProductVariant @key(fields: "sku") {
sku: String! @external
externalPrice: Money @shareable
}

type Money {
centAmount: Int!
currencyCode: String!
}
`;

resolvers = {
ProductVariant: {
__resolveReference: resolveVariantPrice,
externalPrice: externalPriceResolver,
},
};
}

The @key(fields: "sku") and @external directives are Apollo Federation directives that tell the gateway how to resolve ProductVariant across subgraphs.

2. 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.ts so each request gets its own batch window:

export const newContext = async ({ request }) => {
const storeContext = readStoreContextFromRequest(request);
return {
storeContext,
priceLoader: createPriceLoader(storeContext.currency),
};
};

3. 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);
};

4. 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
});
};

5. Register in the gateway

Add the pricing service as a subgraph in your gateway configuration. After deployment, the supergraph schema will include the externalPrice field on every ProductVariant.

The frontend can then query external prices alongside regular product data in a single GraphQL request:

query Product($slug: String!) {
product(slug: $slug) {
variants {
sku
price { centAmount currencyCode }
externalPrice { centAmount currencyCode }
}
}
}

Further reading