Skip to content

New: AI agent integration via Model Context Protocol (MCP).Learn more

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 { 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! @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:

    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),
    };
    };
  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. Compose into the supergraph

    For local development, add the pricing service to the composition task in backend/services/graphql-gateway/Taskfile.yaml and recompose the local supergraph:

    Terminal window
    task -d backend/services/graphql-gateway supergraph

    In production the router polls the supergraph from the Hive CDN; the new subgraph joins it through the service’s hive_schema_publish Terraform resource. Once composed, the supergraph schema includes 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 }
    }
    }
    }