jsonapi

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Use With django-drf

与django-drf配合使用

This skill focuses on spec compliance. For implementation patterns (ViewSets, Serializers, Filters), use
django-drf
skill together with this one.
SkillFocus
jsonapi
What the spec requires (MUST/MUST NOT rules)
django-drf
How to implement it in DRF (code patterns)
When creating/modifying endpoints, invoke BOTH skills.

本技能专注于规范合规性。若需了解实现模式(ViewSets、Serializers、Filters),请将本技能与
django-drf
技能结合使用。
技能核心关注点
jsonapi
规范的强制要求(MUST/MUST NOT规则)
django-drf
如何在DRF中实现(代码模式)
创建/修改端点时,请同时调用这两个技能。

Before Implementing/Reviewing

实现/审核前准备

ALWAYS validate against the latest spec before creating or modifying endpoints:
在创建或修改端点前,务必依据最新规范进行验证:

Option 1: Context7 MCP (Preferred)

选项1:Context7 MCP(推荐)

If Context7 MCP is available, query the JSON:API spec directly:
mcp_context7_resolve-library-id(query="jsonapi specification")
mcp_context7_query-docs(libraryId="<resolved-id>", query="[specific topic: relationships, errors, etc.]")
若Context7 MCP可用,可直接查询JSON:API规范:
mcp_context7_resolve-library-id(query="jsonapi specification")
mcp_context7_query-docs(libraryId="<resolved-id>", query="[specific topic: relationships, errors, etc.]")

Option 2: WebFetch (Fallback)

选项2:WebFetch(备选)

If Context7 is not available, fetch from the official spec:
WebFetch(url="https://jsonapi.org/format/", prompt="Extract rules for [specific topic]")
This ensures compliance with the latest JSON:API version, even after spec updates.

若Context7不可用,可从官方规范获取内容:
WebFetch(url="https://jsonapi.org/format/", prompt="Extract rules for [specific topic]")
这能确保即使规范更新,也能遵循最新版本的JSON:API要求。

Critical Rules (NEVER Break)

关键规则(绝对不可违反)

Document Structure

文档结构

  • NEVER include both
    data
    and
    errors
    in the same response
  • ALWAYS include at least one of:
    data
    ,
    errors
    ,
    meta
  • ALWAYS use
    type
    and
    id
    (string) in resource objects
  • NEVER include
    id
    when creating resources (server generates it)
  • 绝对不可在同一响应中同时包含
    data
    errors
  • 必须至少包含以下一项:
    data
    errors
    meta
  • 资源对象中必须使用
    type
    id
    (字符串类型)
  • 创建资源时绝对不可包含
    id
    (由服务器生成)

Content-Type

内容类型

  • ALWAYS use
    Content-Type: application/vnd.api+json
  • ALWAYS use
    Accept: application/vnd.api+json
  • NEVER add parameters to media type without
    ext
    /
    profile
  • 必须使用
    Content-Type: application/vnd.api+json
  • 必须使用
    Accept: application/vnd.api+json
  • 绝对不可在媒体类型中添加未带有
    ext
    /
    profile
    的参数

Resource Objects

资源对象

  • ALWAYS use string for
    id
    (even if UUID)
  • ALWAYS use lowercase kebab-case for
    type
  • NEVER put
    id
    or
    type
    inside
    attributes
  • NEVER include foreign keys in
    attributes
    - use
    relationships
  • id
    必须为字符串类型(即使是UUID)
  • type
    必须使用小写短横线命名法(kebab-case)
  • 绝对不可将
    id
    type
    放在
    attributes
  • 绝对不可在
    attributes
    中包含外键 - 请使用
    relationships

Relationships

关联关系

  • ALWAYS include at least one of:
    links
    ,
    data
    , or
    meta
  • ALWAYS use resource linkage format:
    {"type": "...", "id": "..."}
  • NEVER use raw IDs in relationships - always use linkage objects
  • 必须至少包含以下一项:
    links
    data
    meta
  • 必须使用资源关联格式:
    {"type": "...", "id": "..."}
  • 绝对不可在关联关系中使用原始ID - 务必使用关联对象

Error Objects

错误对象

  • ALWAYS return errors as array:
    {"errors": [...]}
  • ALWAYS include
    status
    as string (e.g.,
    "400"
    , not
    400
    )
  • ALWAYS include
    source.pointer
    for field-specific errors

  • 必须以数组形式返回错误:
    {"errors": [...]}
  • status
    必须为字符串类型(例如:
    "400"
    ,而非
    400
  • 字段相关错误必须包含
    source.pointer

HTTP Status Codes (Mandatory)

HTTP状态码(强制要求)

OperationSuccessAsyncConflictNot FoundForbiddenBad Request
GET
200
--
404
403
400
POST
201
202
409
404
403
400
PATCH
200
202
409
404
403
400
DELETE
200
/
204
202
-
404
403
-
操作成功异步冲突未找到禁止访问错误请求
GET
200
--
404
403
400
POST
201
202
409
404
403
400
PATCH
200
202
409
404
403
400
DELETE
200
/
204
202
-
404
403
-

When to Use Each

各状态码适用场景

CodeUse When
200 OK
Successful GET, PATCH with response body, DELETE with response
201 Created
POST created resource (MUST include
Location
header)
202 Accepted
Async operation started (return task reference)
204 No Content
Successful DELETE, PATCH with no response body
400 Bad Request
Invalid query params, malformed request, unknown fields
403 Forbidden
Authentication ok but no permission, client-generated ID rejected
404 Not Found
Resource doesn't exist OR RLS hides it (never reveal which)
409 Conflict
Duplicate ID, type mismatch, relationship conflict
415 Unsupported
Wrong Content-Type header

状态码适用场景
200 OK
成功的GET请求、带响应体的PATCH请求、带响应体的DELETE请求
201 Created
POST请求创建资源成功(必须包含
Location
响应头)
202 Accepted
异步操作已启动(返回任务引用)
204 No Content
成功的DELETE请求、无响应体的PATCH请求
400 Bad Request
无效的查询参数、格式错误的请求、未知字段
403 Forbidden
认证通过但无权限、客户端生成的ID被拒绝
404 Not Found
资源不存在或被RLS隐藏(绝不可泄露具体原因)
409 Conflict
重复ID、类型不匹配、关联关系冲突
415 Unsupported
Content-Type请求头错误

Document Structure

文档结构

Success Response (Single)

成功响应(单个资源)

json
{
  "data": {
    "type": "providers",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "alias": "Production",
      "connected": true
    },
    "relationships": {
      "tenant": {
        "data": {"type": "tenants", "id": "..."}
      }
    },
    "links": {
      "self": "/api/v1/providers/550e8400-..."
    }
  },
  "links": {
    "self": "/api/v1/providers/550e8400-..."
  }
}
json
{
  "data": {
    "type": "providers",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "alias": "Production",
      "connected": true
    },
    "relationships": {
      "tenant": {
        "data": {"type": "tenants", "id": "..."}
      }
    },
    "links": {
      "self": "/api/v1/providers/550e8400-..."
    }
  },
  "links": {
    "self": "/api/v1/providers/550e8400-..."
  }
}

Success Response (List)

成功响应(资源列表)

json
{
  "data": [
    {"type": "providers", "id": "...", "attributes": {...}},
    {"type": "providers", "id": "...", "attributes": {...}}
  ],
  "links": {
    "self": "/api/v1/providers?page[number]=1",
    "first": "/api/v1/providers?page[number]=1",
    "last": "/api/v1/providers?page[number]=5",
    "prev": null,
    "next": "/api/v1/providers?page[number]=2"
  },
  "meta": {
    "pagination": {"count": 100, "pages": 5}
  }
}
json
{
  "data": [
    {"type": "providers", "id": "...", "attributes": {...}},
    {"type": "providers", "id": "...", "attributes": {...}}
  ],
  "links": {
    "self": "/api/v1/providers?page[number]=1",
    "first": "/api/v1/providers?page[number]=1",
    "last": "/api/v1/providers?page[number]=5",
    "prev": null,
    "next": "/api/v1/providers?page[number]=2"
  },
  "meta": {
    "pagination": {"count": 100, "pages": 5}
  }
}

Error Response

错误响应

json
{
  "errors": [
    {
      "status": "400",
      "code": "invalid",
      "title": "Invalid attribute",
      "detail": "UID must be 12 digits for AWS accounts",
      "source": {"pointer": "/data/attributes/uid"}
    }
  ]
}

json
{
  "errors": [
    {
      "status": "400",
      "code": "invalid",
      "title": "Invalid attribute",
      "detail": "UID must be 12 digits for AWS accounts",
      "source": {"pointer": "/data/attributes/uid"}
    }
  ]
}

Query Parameters

查询参数

FamilyFormatExample
page
page[number]
,
page[size]
?page[number]=2&page[size]=25
filter
filter[field]
,
filter[field__op]
?filter[status]=FAIL
sort
Comma-separated,
-
for desc
?sort=-inserted_at,name
fields
fields[type]
?fields[providers]=id,alias
include
Comma-separated paths
?include=provider,scan.task
类别格式示例
page
page[number]
,
page[size]
?page[number]=2&page[size]=25
filter
filter[field]
,
filter[field__op]
?filter[status]=FAIL
sort
逗号分隔,
-
表示降序
?sort=-inserted_at,name
fields
fields[type]
?fields[providers]=id,alias
include
逗号分隔的路径
?include=provider,scan.task

Rules

规则

  • MUST return
    400
    for unsupported query parameters
  • MUST return
    400
    for unsupported
    include
    paths
  • MUST return
    400
    for unsupported
    sort
    fields
  • MUST NOT include extra fields when
    fields[type]
    is specified

  • 对于不支持的查询参数,必须返回
    400
  • 对于不支持的
    include
    路径,必须返回
    400
  • 对于不支持的
    sort
    字段,必须返回
    400
  • 当指定
    fields[type]
    时,绝对不可包含额外字段

Common Violations (AVOID)

常见违规情况(需避免)

ViolationWrongCorrect
ID as integer
"id": 123
"id": "123"
Type as camelCase
"type": "providerGroup"
"type": "provider-groups"
FK in attributes
"tenant_id": "..."
"relationships": {"tenant": {...}}
Errors not array
{"error": "..."}
{"errors": [{"detail": "..."}]}
Status as number
"status": 400
"status": "400"
Data + errors
{"data": ..., "errors": ...}
Only one or the other
Missing pointer
{"detail": "Invalid"}
{"detail": "...", "source": {"pointer": "..."}}

违规行为错误示例正确示例
ID为整数
"id": 123
"id": "123"
Type使用驼峰命名
"type": "providerGroup"
"type": "provider-groups"
属性中包含外键
"tenant_id": "..."
"relationships": {"tenant": {...}}
错误未以数组形式返回
{"error": "..."}
{"errors": [{"detail": "..."}]}
Status为数字
"status": 400
"status": "400"
同时包含Data和Errors
{"data": ..., "errors": ...}
仅包含其中一项
缺少source.pointer
{"detail": "Invalid"}
{"detail": "...", "source": {"pointer": "..."}}

Relationship Updates

关联关系更新

To-One Relationship

一对一关联关系

http
PATCH /api/v1/providers/123/relationships/tenant
Content-Type: application/vnd.api+json

{"data": {"type": "tenants", "id": "456"}}
To clear:
{"data": null}
http
PATCH /api/v1/providers/123/relationships/tenant
Content-Type: application/vnd.api+json

{"data": {"type": "tenants", "id": "456"}}
清空关联:
{"data": null}

To-Many Relationship

一对多关联关系

OperationMethodBody
Replace allPATCH
{"data": [{...}, {...}]}
Add membersPOST
{"data": [{...}]}
Remove membersDELETE
{"data": [{...}]}

操作请求方法请求体
替换所有关联PATCH
{"data": [{...}, {...}]}
添加成员POST
{"data": [{...}]}
删除成员DELETE
{"data": [{...}]}

Compound Documents (
include
)

复合文档(
include

When using
?include=provider
:
json
{
  "data": {
    "type": "scans",
    "id": "...",
    "relationships": {
      "provider": {
        "data": {"type": "providers", "id": "prov-123"}
      }
    }
  },
  "included": [
    {
      "type": "providers",
      "id": "prov-123",
      "attributes": {"alias": "Production"}
    }
  ]
}
当使用
?include=provider
时:
json
{
  "data": {
    "type": "scans",
    "id": "...",
    "relationships": {
      "provider": {
        "data": {"type": "providers", "id": "prov-123"}
      }
    }
  },
  "included": [
    {
      "type": "providers",
      "id": "prov-123",
      "attributes": {"alias": "Production"}
    }
  ]
}

Rules

规则

  • Every included resource MUST be reachable via relationship chain from primary data
  • MUST NOT include orphan resources
  • MUST NOT duplicate resources (same type+id)

  • 每个包含的资源必须能通过主数据的关联链访问到
  • 绝对不可包含孤立资源
  • 绝对不可重复包含资源(相同type+id)

Spec Reference

规范参考

  • Full Specification: https://jsonapi.org/format/
  • Implementation: Use
    django-drf
    skill for DRF-specific patterns
  • Testing: Use
    prowler-test-api
    skill for test patterns
  • 完整规范https://jsonapi.org/format/
  • 实现:使用
    django-drf
    技能获取DRF特定的实现模式
  • 测试:使用
    prowler-test-api
    技能获取测试模式