mcpField
S
spree-legacy-api-v2

spree-legacy-api-v2

github.com/spree开发10109 次安装4 周前更新
代码仓库

关于 spree-legacy-api-v2

spree-legacy-api-v2 面向维护 Spree API v2 集成或迁移至 v3 的开发者,说明旧版接口结构与差异。内容覆盖认证、响应格式及逐端点迁移要点。

主要功能

  1. 01Storefront 与 Platform API 差异
  2. 02OAuth2 认证与令牌请求头
  3. 03JSON:API 响应结构与分页
  4. 04v2 至 v3 的认证、ID 和筛选变更
  5. 05旧版 SDK 与 Webhook 迁移说明

适用场景

  1. 01维护现有的 v2 集成
  2. 02规划逐步迁移到 API v3

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/spree/agent-skills --skill spree-legacy-api-v2

安装后在 Claude Code 中输入/spree-legacy-api-v2确认已加载。

详细介绍

Spree API v2 — 旧版

默认建议:不要基于 v2 开发新功能。 Spree 5.4+ 将 API v3 作为面向未来的 API;v2 仍可使用,但已冻结功能。新端点、新认证模式(publishable + secret + JWT)、带前缀的 ID、expand、类型化 SDK——这些都属于 v3。新的集成应从 v3 开始。

此技能适用于两种实际情况:

  1. 你接手了一个 v2 集成,需要维护它。
  2. 你正在从 v2 迁移到 v3,需要了解变更内容。

如果两种情况都不适用,请改用 spree-api-v3 技能。

v2 的形式

/api/v2/ 下有两个不同的 API 界面:

界面路径面向对象
Storefront API/api/v2/storefront/*面向客户——购物车、商品、结账
Platform API/api/v2/platform/*管理/后台——完整的 CRUD

两者都采用 JSON:API 风格(https://jsonapi.org/)——使用包含 data、attributes、relationships、included 的严格封装。封装形式与 v3 不同。

v2 中的认证
界面请求头令牌
Storefront(匿名浏览)无公开访问
Storefront(访客购物车)X-Spree-Order-Token购物车的订单令牌
Storefront(已登录客户)Authorization: Bearer <oauth_token>OAuth2 客户令牌
Platform(管理员)Authorization: Bearer <oauth_token>OAuth2 管理员令牌

v2 使用 OAuth2 Doorkeeper 签发令牌——通过 /spree_oauth/token 端点使用 password 或 client_credentials 授权方式。没有 publishable key,也没有 secret key。OAuth 作用域存在,但粒度较粗(admin、write、read——Platform API 需要 read/admin 才能读取,需要 write/admin 才能写入);不像 v3 的 API key 作用域那样细分为 read_products/write_orders。

# Get a Platform API token (admin)
curl -X POST https://my-spree.example.com/spree_oauth/token \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data "grant_type=password&[email protected]&password=…"
# => { "access_token": "…", "token_type": "Bearer", "expires_in": 2592000, ... }
# (tokens last 1 month by default — `access_token_expires_in 1.month`)

# Use it
curl -H "Authorization: Bearer …" \
     https://my-spree.example.com/api/v2/platform/orders
封装形式
{
  "data": {
    "id": "42",                          // raw integer PK as string
    "type": "product",
    "attributes": {
      "name": "Cool shirt",
      "price": "29.99",
      "currency": "USD",
      "created_at": "2025-01-01T00:00:00Z"
    },
    "relationships": {
      "variants": {
        "data": [{ "id": "100", "type": "variant" }]
      }
    }
  },
  "included": [
    {
      "id": "100",
      "type": "variant",
      "attributes": { "sku": "COOL-S", ... }
    }
  ],
  "meta": { "total_count": 152, "total_pages": 7 }
}

与 v3 相比:

  • v2:原始整数 ID("42")。v3:带前缀的 ID("prod_…")。
  • v2:嵌套的 attributes + relationships。v3:顶层扁平字段。
  • v2:include 查询参数将相关资源提取到 included 数组中。v3:expand 查询参数将它们直接内联到响应中(?expand=variants,media,点号嵌套最多 4 层)。
  • v2(Platform API):筛选条件使用 filter[name_cont]=…。v3:原理相同,但使用 q[name_cont]=…(Ransack)。Storefront API 则使用各端点固定的筛选条件名称——见下文步骤 4。
  • v2:排序使用 sort=-created_at。v3:完全相同——sort=-created_at 可原样使用(v3 ResourceController 会在内部将 -field JSON:API 表示法转换为 Ransack s)。
分页
GET /api/v2/storefront/products?page=2&per_page=25

meta.total_count、meta.total_pages。v2 不支持键集/游标分页,仅支持偏移分页。

使用 v2 时

“我需要在 v2 响应中添加字段”

装饰 JSON:API 序列化器(底层使用 jsonapi-serializer gem):

module Spree::V2::Storefront::ProductSerializerDecorator
  def self.prepended(base)
    base.attribute :custom_field do |product|
      product.custom_field_value
    end
  end
  Spree::V2::Storefront::ProductSerializer.prepend self
end
“我需要一个新的 v2 端点”

不要添加到 v2。改为添加到 v3——有关 spree:api_resource 生成器,请参阅 spree-resource 技能。如果你的 v2 客户端确实无法与 v3 通信,可以编写一个轻量兼容封装,返回 v2 封装形式的 JSON,但内部从 v3 资源读取数据。

“v2 返回了错误,错误格式是什么?”
{
  "error": "The resource was not found.",
  "errors": { ... }   // on 422
}

普通 JSON,而不是 JSON:API 错误对象。v3 使用结构化的 { error: { code, message, details } } 封装——请参阅 spree-api-v3。

从 v2 迁移到 v3

迁移按端点逐个进行。无需一次性全部切换;v2 和 v3 可以共存。

步骤 1:迁移身份验证
v2v3
使用 OAuth2 密码授权登录客户使用 JWT 在 /api/v3/store/auth/login 登录(返回 token + refresh_token + user)
使用 OAuth2 client_credentials 授权管理应用使用具有指定权限范围的密钥(sk_*)
Authorization: Bearer <token>X-Spree-Api-Key: <pk_…|sk_…> + 可选的 Authorization: Bearer <jwt>
访客购物车使用 X-Spree-Order-Token仍使用 X-Spree-Token(已重命名)

对于管理应用:通过管理界面生成密钥(Settings → Developers → API Keys,密钥类型为 'Secret'),并设置所需的权限范围。完全弃用 OAuth2。

对于客户流程:将 OAuth2 登录调用替换为 JWT 登录。新流程也会返回刷新令牌——请参阅管理端身份验证文档,了解基于 Cookie 的刷新模式。

步骤 2:迁移 ID

v2 将整数 ID 作为字符串返回;v3 返回带前缀的 ID。如果客户端存储了 ID:

// Old
const productId = response.data.id   // "42"

// New
const productId = response.data.id   // "prod_86Rf07xd4z"

如果你已在自己的数据库中持久化 v2 ID,并且需要根据 v3 响应查找这些 ID,整数 PK 保持不变——只需使用整数调用 v3 搜索端点:

GET /api/v3/admin/products?q[id_eq]=42

请注意,在客户端代码中公开原始整数 ID 是 v2 的反模式,v3 已对此进行修正;新 ID 可安全用于 URL,且不会泄露记录数量。

步骤 3:拆除响应封装
// v2 JSON:API
const product = response.data
const name = product.attributes.name
const price = product.attributes.price
const variantIds = product.relationships.variants.data.map(v => v.id)
const variants = response.included.filter(r => r.type === 'variant')

// v3 flat
const product = response   // single endpoint — no envelope
const name = product.name
const price = product.price
const defaultVariantId = product.default_variant_id   // direct field
// With ?expand=variants: product.variants is an array of full variant objects

如果无法一次性重构所有调用点,可以编写一个轻量级适配器:

function unwrapV2<T>(response: V2Response<T>): T {
  return {
    id: response.data.id,
    ...response.data.attributes,
    ...buildRelationships(response.data.relationships, response.included),
  } as T
}
步骤 4:筛选语法
v2v3
filter[name_cont]=shirt(平台 API)q[name_cont]=shirt
filter[price_gteq]=20(平台 API)q[price_gteq]=20
sort=-created_atsort=-created_at(不变)

对于平台 API,filter[...] 键是 Ransack 谓词,与 v3 的 q[...] 一一对应——filter[name_cont] 变为 q[name_cont]。Storefront API 不使用 Ransack:每个端点都有由 finder 类处理的固定筛选名称,因此需要进行对应转换——filter[name] → q[name_cont](或 q[search]),filter[taxons] → q[in_categories],filter[price]=10,50 → q[price_gte]=10&q[price_lte]=50。

@spree/sdk 将扁平的 Ransack 谓词作为带类型的列表参数接受,例如 client.products.list({ name_cont: 'shirt' }),并自动生成 q[name_cont]=...——详见 spree-typescript-sdk。

步骤 5:切换 SDK

如果你正在使用旧版 @spree/storefront-api-v2-sdk 包(JS),请将其替换为 @spree/sdk(Store API)或 @spree/admin-sdk(Admin API)。新版 SDK 具有类型支持和内置重试功能,并遵循 v3 其他接口使用的相同协议。

步骤 6:Webhooks(如适用)

如果你接收 v2 Webhooks:v2 Webhooks 使用原始 ID 和旧版负载格式触发。v3 Webhooks 使用带前缀的 ID,以及 {id, name, created_at, data, metadata} 封装格式。如果将端点切换为 v3,Webhook 接收器必须能够处理新的负载格式——详见 spree-events-webhooks。

v2 何时停止提供

spree_api 不再捆绑 v2。从 Spree 5.5 开始,v2 位于单独的弃用 gem spree_legacy_api_v2 中,该 gem 可与 Spree 5 配合使用。若要继续运行现有的 v2 集成,请添加此 gem(bundle add spree_legacy_api_v2);对于全新应用,还需运行 bin/rails g spree:legacy_api_v2:install 来安装其迁移(从早期 Spree 版本升级的应用已包含这些迁移)。计划在下一个主版本中移除 API v2,且不会再添加新功能——新字段、端点和能力(例如 Markets、新定价引擎)仅会在 v3 中推出。

如果你维护着重要的 v2 集成,请安排迁移;否则只会与后续版本差距越来越大。

延伸阅读

  • v3 API 协议:spree-api-v3 技能——目标文档。
  • v3 TypeScript SDK:spree-typescript-sdk 技能。
  • 在 v3 上添加自定义端点:spree-resource 技能。
  • v2 源码:spree_legacy_api_v2 gem——控制器和序列化器(基于 jsonapi-serializer)。v2 不再随 spree_api 一同发布。
  • v2 OpenAPI 规范:docs/api-reference/storefront.yaml 和 docs/api-reference/platform.yaml。v3 规范为 docs/api-reference/store.yaml(也随 @spree/docs npm 包一同发布,位于 node_modules/@spree/docs/dist/api-reference/store.yaml)。

评论

支持 Markdown