Skip to content
AI & Agents
Skill

/commerce-app-api-mesh

Scaffold or update an Adobe API Mesh configuration (mesh.json) in front of a Commerce app: add GraphQL/OpenAPI sources, extend an existing Commerce GraphQL type with a new field, and wire a cross-source resolver for it. Use when the user mentions API Mesh, mesh.json, extending a

From plugin
adobe-skills
182154 skills4 MCP
Install
$ npx -y skills add adobe/skills --skill commerce-app-api-mesh --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/commerce-app-api-mesh

Context preview

The summary Claude sees to decide when to auto-load this skill.

Scaffold or update an Adobe API Mesh configuration (mesh.json) in front of a Commerce app: add GraphQL/OpenAPI sources, extend an existing Commerce GraphQL type with a new field, and wire a cross-source resolver for it. Use when the user mentions API Mesh, mesh.json, extending a

SKILL.md

commerce-app-api-mesh.SKILL.md
name: commerce-app-api-mesh
description: >
  Scaffold or update an Adobe API Mesh configuration (mesh.json) in front of
  a Commerce app: add GraphQL/OpenAPI sources, extend an existing Commerce
  GraphQL type with a new field, and wire a cross-source resolver for it.
  Use when the user mentions API Mesh, mesh.json, extending a Commerce
  GraphQL type (e.g. adding a field to Order/CustomerOrder/Product), or
  stitching a runtime action's data into the storefront's GraphQL schema.
license: Apache-2.0
compatibility: >
  Requires the api-mesh CLI plugin (aio plugins install
  @adobe/aio-cli-plugin-api-mesh). If wrapping a runtime action as a source,
  that action must already be built and deployed.
metadata:
  author: adobe

Wire API Mesh in Front of a Commerce App

Composes Commerce's own GraphQL API and this app's runtime actions into a single mesh schema. Two moves this skill covers: exposing a runtime action as a mesh source, and extending an existing Commerce type with a field resolved by delegating to that source.

This skill assumes general API Mesh knowledge (`mesh.json` anatomy, handler types, transforms, hooks, secrets, CORS, generic declarative/programmatic resolvers). If any of that is unfamiliar, load it from Adobe's own material first — see [References](#references) — rather than guessing at syntax. None of that material covers extending an existing Commerce type via `additionalResolvers` (`targetTypeName`/`sourceTypeName`/`requiredSelectionSet`/`sourceSelectionSet`) or wrapping an aio-commerce-sdk runtime action as a mesh source — that's what follows.

Prerequisites

  • `aio plugins install @adobe/aio-cli-plugin-api-mesh` is installed.
  • If exposing a runtime action as a source, it's already built and deployed with a real, reachable HTTPS endpoint — a source pointing at an undeployed action fails opaquely.
  • Check whether a mesh already exists for this workspace: `aio api-mesh:get`. "No mesh found" → you'll `create`; otherwise you're editing an existing `mesh.json` and will `update`.

Step 1 — Confirm schema shapes via introspection

Before writing `additionalTypeDefs` or `additionalResolvers`, introspect the Commerce (or other) GraphQL source you're extending. Don't assume a type/field name from memory or a similar-sounding convention — near-miss names produce a mesh that builds successfully but whose resolver never fires.

curl -s -X POST "<graphql-endpoint>" -H "Content-Type: application/json" \
  -d '{"query":"{ __type(name: \"<TargetType>\") { fields { name } } }"}'

Step 2 — Scaffold sources

{
  "name": "Commerce",
  "handler": {
    "graphql": {
      "endpoint": "<commerce-graphql-endpoint>",
      "operationHeaders": { "Authorization": "{context.headers.authorization}" }
    }
  }
}

Include `operationHeaders` by default on any source whose schema has customer-, cart-, or session-scoped fields — API Mesh does **not** forward the caller's `Authorization` header automatically. Omitting it makes every authenticated query fail with the backend's own generic "not authorized" error, indistinguishable from an invalid token.

To wrap a runtime action, write a small static OpenAPI document describing just its endpoint and reference it by relative path:

{
  "name": "<SourceName>",
  "handler": { "openapi": { "source": "./mesh/<source>.json" } }
}

The OpenAPI document itself needs enough shape for the mesh to generate a Query field from it — not just the pointer above. Minimal example for a single-endpoint runtime action:

{
  "openapi": "3.0.0",
  "info": { "title": "<SourceName>", "version": "1.0.0" },
  "servers": [{ "url": "<runtime-action-base-url>" }],
  "paths": {
    "/<action-path>": {
      "get": {
        "operationId": "<sourceField>",
        "parameters": [
          {
            "name": "<arg>",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "<resultField>": { "type": "string" } }
                }
              }
            }
          }
        }
      }
    }
  }
}

`operationId` becomes the Query field name — it must match `sourceFieldName` in Step 3's resolver exactly, or the resolver builds successfully but never fires.

The declared response schema must match what the action actually returns — the mesh parses according to what you declare, it doesn't reshape data.

Step 3 — Extend a type and wire the resolver

"additionalTypeDefs": "extend type <TargetType> { <newField>: String }",
"additionalResolvers": [
  {
    "targetTypeName": "<TargetType>",
    "targetFieldName": "<newField>",
    "sourceName": "<SourceName>",
    "sourceTypeName": "Query",
    "sourceFieldName": "<sourceField>",
    "requiredSelectionSet": "{ <keyField> }",
    "sourceArgs": { "<arg>": "{root.<keyField>}" },
    "sourceSelectionSet": "{ <resultField> }",
    "result": "<resultField>"
  }
]

Always pair `sourceSelectionSet` with `result` when extracting a scalar from an object-returning source field — never use `result` alone. The `result`-only path builds its selection set by hand instead of via the GraphQL parser, and breaks with `"No type was found for field node ... __typename"` specifically when the target field resolves inside a list (e.g. a parent's `items[].<newField>`). A direct root-query call to the same source field succeeds even when this bug is present, so that test alone isn't sufficient proof the resolver works.

Step 4 — Deploy and verify

If you already know a browser-based app will call this mesh, decide `responseConfig.CORS` now, before your first deploy — the browser-verification tier below exists to catch a missed CORS config, but deciding upfront avoids a second deploy cycle.

The first `aio api-mes

Read more
Ships withadobe-skills

Repository of Adobe skills for AI coding agents.

Get the whole plugin

Other skills on adobe-skills.