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
- 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