You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在CRNK(JSON-API)中实现子资源关系且不使用顶级仓库

Got it, let's walk through how to build sub-resource relationships with CRNK while making sure everything stays fully compliant with the JSON-API spec. We'll use your queue + historical time properties example to keep things concrete, no extra business fluff.

1. Define Your Resource Classes First

Start by creating your core Queue resource and its sub-resource (let's call it QueueHistory for clarity) with CRNK's annotations. This lays the foundation for JSON-API's resource structure.

// Queue.java
@JsonApiResource(type = "queues")
public class Queue {
    @JsonApiId
    private Long id;
    private String name;
    private String description;

    // Define the TO_MANY relationship to QueueHistory
    @JsonApiRelation(opposite = "queue", kind = RelationKind.TO_MANY)
    private List<QueueHistory> history;

    // Getters and setters omitted for brevity
}

// QueueHistory.java
@JsonApiResource(type = "queue-histories")
public class QueueHistory {
    @JsonApiId
    private Long id;
    private LocalDateTime timestamp;
    private String eventType; // e.g., "CREATED", "UPDATED"

    // Define the inverse TO_ONE relationship back to Queue
    @JsonApiRelation(opposite = "history", kind = RelationKind.TO_ONE)
    private Queue queue;

    // Getters and setters omitted for brevity
}

Key note: The type values ("queues", "queue-histories") must be pluralized and consistent—this is a strict JSON-API requirement.

2. Implement Resource Repositories

CRNK relies on repositories to handle data access and relationship resolution. Create repositories for both resources, extending CRNK's base repository classes. If you're using JPA, you can leverage JpaRepositoryWrapper to avoid boilerplate.

// QueueRepository.java
public class QueueRepository extends JpaRepositoryWrapper<Queue, Long> {
    public QueueRepository(EntityManager em) {
        super(Queue.class, em);
    }
}

// QueueHistoryRepository.java
public class QueueHistoryRepository extends JpaRepositoryWrapper<QueueHistory, Long> {
    public QueueHistoryRepository(EntityManager em) {
        super(QueueHistory.class, em);
    }

    // Optional: Add a method to fetch history for a specific queue (CRNK can auto-generate this, but explicit is okay)
    public List<QueueHistory> findByQueue(Queue queue) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<QueueHistory> query = cb.createQuery(QueueHistory.class);
        Root<QueueHistory> root = query.from(QueueHistory.class);
        query.where(cb.equal(root.get("queue"), queue));
        return getEntityManager().createQuery(query).getResultList();
    }
}
3. Validate JSON-API Compliance

Once your setup is done, test the endpoints to ensure they adhere to JSON-API standards:

  • Fetch a queue with its history: Send GET /queues/1?include=history
    The response will include a top-level included array with all related queue-histories resources, which is exactly what JSON-API requires for compound documents.
  • Fetch only the queue's history: Send GET /queues/1/history
    This returns a JSON-API document with data as an array of queue-histories resources, no extra fluff.
  • Update a relationship: Use PATCH /queues/1/relationships/history with a JSON-API compliant payload to add/remove history entries—CRNK handles the relationship persistence automatically if your repository supports it.
4. Key Compliance Checks to Remember
  • Always specify the opposite attribute in @JsonApiRelation—this ensures JSON-API's bidirectional relationship rules are followed.
  • Use the correct RelationKind (TO_ONE/TO_MANY) to match your relationship cardinality; this affects how CRNK serializes the response.
  • Never skip the @JsonApiId annotation—JSON-API requires every resource to have a unique id field.

内容的提问来源于stack exchange,提问作者DaveJohnston

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:52:32