Claude-skill-registry jsonapi

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/jsonapi" ~/.claude/skills/majiayu000-claude-skill-registry-jsonapi && rm -rf "$T"
manifest: skills/data/jsonapi/SKILL.md
source content

Use With 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.


Before Implementing/Reviewing

ALWAYS validate against the latest spec before creating or modifying endpoints:

Option 1: Context7 MCP (Preferred)

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.]")

Option 2: WebFetch (Fallback)

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.


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)

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

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

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

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

HTTP Status Codes (Mandatory)

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
-

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

Document Structure

Success Response (Single)

{
  "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)

{
  "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

{
  "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

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

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": "..."}}

Relationship Updates

To-One Relationship

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

{"data": {"type": "tenants", "id": "456"}}

To clear:

{"data": null}

To-Many Relationship

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

Compound Documents (
include
)

When using

?include=provider
:

{
  "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)

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