GraphQL API¶
即将推出
GraphQL API 计划在未来版本(v0.2)中发布。以下文档描述了计划的实现,可能会有变更。
GraphQL API 提供灵活、类型安全的查询语言,用于访问您的 R Commerce 数据。
概览¶
GraphQL 允许客户端请求所需的确切数据,减少过度获取并实现强大的数据获取模式。
端点¶
认证¶
在 Authorization 头中包含您的 API 密钥:
POST /graphql HTTP/1.1
Host: api.rcommerce.app
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
查询¶
产品查询¶
检索具有灵活字段选择的产品。
基本查询¶
query GetProducts {
products(first: 10) {
edges {
node {
id
title
slug
price
currency
inventoryQuantity
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
带变体和图片¶
query GetProductDetails($id: ID!) {
product(id: $id) {
id
title
description
price
compareAtPrice
currency
status
vendor
tags
inventoryQuantity
variants(first: 10) {
edges {
node {
id
title
sku
price
inventoryQuantity
options {
name
value
}
}
}
}
images(first: 5) {
edges {
node {
id
url
altText
position
}
}
}
collections(first: 5) {
edges {
node {
id
title
slug
}
}
}
}
}
变量¶
订单查询¶
query GetOrders($first: Int!, $after: String) {
orders(first: $first, after: $after, sortKey: CREATED_AT, reverse: true) {
edges {
node {
id
orderNumber
email
totalPrice
currency
financialStatus
fulfillmentStatus
createdAt
customer {
id
email
firstName
lastName
}
lineItems(first: 5) {
edges {
node {
title
quantity
price
total
}
}
}
shippingAddress {
firstName
lastName
address1
city
country
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
客户查询¶
query GetCustomers($query: String) {
customers(first: 20, query: $query) {
edges {
node {
id
email
firstName
lastName
phone
acceptsMarketing
ordersCount
totalSpent
defaultAddress {
address1
city
country
}
addresses {
edges {
node {
id
address1
city
isDefaultShipping
}
}
}
}
}
}
}
购物车查询¶
query GetCart($token: String!) {
cart(token: $token) {
id
token
currency
subtotalPrice
totalTax
totalShipping
totalPrice
lineItems {
edges {
node {
id
quantity
title
variant {
id
title
price
product {
id
title
images(first: 1) {
edges {
node {
url
}
}
}
}
}
}
}
}
}
}
变更¶
创建购物车¶
添加到购物车¶
mutation AddToCart($token: String!, $lines: [CartLineInput!]!) {
cartLinesAdd(cartToken: $token, lines: $lines) {
cart {
id
totalPrice
lineItems {
edges {
node {
id
quantity
title
}
}
}
}
userErrors {
field
message
}
}
}
变量¶
{
"token": "cart_abc123",
"lines": [
{
"merchandiseId": "gid://rcommerce/ProductVariant/550e8400-e29b-41d4-a716-446655440001",
"quantity": 2
}
]
}
更新购物车行¶
mutation UpdateCartLine($token: String!, $lineId: ID!, $quantity: Int!) {
cartLinesUpdate(cartToken: $token, lines: [{id: $lineId, quantity: $quantity}]) {
cart {
id
totalPrice
}
userErrors {
field
message
}
}
}
从购物车移除¶
mutation RemoveFromCart($token: String!, $lineIds: [ID!]!) {
cartLinesRemove(cartToken: $token, lineIds: $lineIds) {
cart {
id
totalPrice
}
userErrors {
field
message
}
}
}
应用优惠券¶
mutation ApplyCoupon($token: String!, $code: String!) {
cartCouponApply(cartToken: $token, code: $code) {
cart {
id
discountCodes
totalPrice
}
userErrors {
field
message
}
}
}
创建结账¶
mutation CreateCheckout($input: CheckoutCreateInput!) {
checkoutCreate(input: $input) {
checkout {
id
token
webUrl
totalPrice
lineItems {
edges {
node {
title
quantity
}
}
}
}
userErrors {
field
message
}
}
}
变量¶
{
"input": {
"lineItems": [
{
"variantId": "gid://rcommerce/ProductVariant/550e8400-e29b-41d4-a716-446655440001",
"quantity": 2
}
],
"email": "customer@example.com",
"shippingAddress": {
"firstName": "John",
"lastName": "Doe",
"address1": "123 Main St",
"city": "New York",
"province": "NY",
"country": "US",
"zip": "10001"
}
}
}
完成结账并支付¶
mutation CheckoutComplete($token: String!, $payment: PaymentInput!) {
checkoutComplete(token: $token, payment: $payment) {
order {
id
orderNumber
totalPrice
financialStatus
}
payment {
id
status
gateway
}
userErrors {
field
message
}
}
}
订阅¶
通过 WebSocket 实时更新(如果启用)。
购物车更新¶
subscription OnCartUpdate($token: String!) {
cartUpdated(token: $token) {
id
totalPrice
lineItems {
edges {
node {
quantity
}
}
}
}
}
订单状态¶
subscription OnOrderUpdate($id: ID!) {
orderUpdated(id: $id) {
id
fulfillmentStatus
financialStatus
fulfillments {
edges {
node {
status
trackingNumber
}
}
}
}
}
片段¶
重用常见的字段选择:
fragment ProductFields on Product {
id
title
slug
price
currency
inventoryQuantity
status
}
fragment CustomerFields on Customer {
id
email
firstName
lastName
acceptsMarketing
}
query GetProductsWithFragment {
products(first: 10) {
edges {
node {
...ProductFields
vendor
tags
}
}
}
}
错误处理¶
GraphQL 即使出错也返回 200 OK。检查 errors 数组:
{
"data": {
"cartLinesAdd": {
"cart": null,
"userErrors": [
{
"field": ["lines", 0, "merchandiseId"],
"message": "产品变体未找到"
}
]
}
}
}
常见错误类型¶
| 错误 | 说明 |
|---|---|
NOT_FOUND |
请求的资源不存在 |
INVALID_INPUT |
输入验证失败 |
INSUFFICIENT_INVENTORY |
库存不足 |
PAYMENT_ERROR |
支付处理失败 |
AUTHENTICATION_ERROR |
凭证无效或缺失 |
RATE_LIMITED |
请求过多 |
速率限制¶
GraphQL 查询按复杂度评级:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1705312800
X-RateLimit-Cost: 10
复杂度计算¶
- 基础成本:1 点
- 每个字段:+1 点
- 嵌套连接:+10 点
- 最大复杂度:每次查询 1000 点
分页¶
对大数据集使用基于光标的分页:
query GetProductsPaginated($first: Int!, $after: String) {
products(first: $first, after: $after) {
edges {
cursor
node {
id
title
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
分页变量¶
模式内省¶
探索模式:
{
__schema {
types {
name
kind
}
queryType {
fields {
name
type {
name
}
}
}
mutationType {
fields {
name
}
}
}
}
获取类型详情:
SDK 示例¶
JavaScript/TypeScript¶
import { GraphQLClient, gql } from 'graphql-request'
const client = new GraphQLClient('https://api.rcommerce.app/graphql', {
headers: {
authorization: 'Bearer YOUR_API_KEY',
},
})
const query = gql`
query GetProduct($id: ID!) {
product(id: $id) {
title
price
}
}
`
const data = await client.request(query, { id: 'gid://rcommerce/Product/123' })
Python¶
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
transport = RequestsHTTPTransport(
url='https://api.rcommerce.app/graphql',
headers={'Authorization': 'Bearer YOUR_API_KEY'}
)
client = Client(transport=transport)
query = gql('''
query GetProduct($id: ID!) {
product(id: $id) {
title
price
}
}
''')
result = client.execute(query, variable_values={'id': 'gid://rcommerce/Product/123'})
Rust¶
use graphql_client::{GraphQLQuery, Response};
use reqwest;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schema.graphql",
query_path = "src/get_product.graphql"
)]
struct GetProduct;
async fn fetch_product(id: &str) -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let variables = get_product::Variables {
id: id.to_string(),
};
let response = client
.post("https://api.rcommerce.app/graphql")
.header("Authorization", "Bearer YOUR_API_KEY")
.json(&GetProduct::build_query(variables))
.send()
.await?;
let response_body: Response<get_product::ResponseData> = response.json().await?;
if let Some(data) = response_body.data {
println!("Product: {:?}", data.product);
}
Ok(())
}
最佳实践¶
- 只请求需要的字段 - 减少负载大小并提高性能
- 使用片段 - 重用常见的选择
- 处理分页 - 不要假设所有数据都在一个请求中
- 检查 userErrors - 始终处理业务逻辑错误
- 缓存响应 - 对可缓存的查询使用 ETags
- 使用变量 - 不要将字符串连接到查询中
与 REST 的比较¶
| 特性 | GraphQL | REST |
|---|---|---|
| 数据获取 | 需要的精确字段 | 固定的响应结构 |
| 多个资源 | 单个请求 | 多个请求 |
| 版本控制 | 模式演进 | URL 版本控制 |
| 内省 | 内置 | 需要文档 |
| 文件上传 | 多部分变更 | 标准 POST |
| 缓存 | 应用层 | HTTP 缓存 |