跳轉到

Resource Revisions

The goal of this pattern is to provide a framework that enables storing multiple revisions for a single resource and also allow other more complex functionality such as deleting revisions that aren't necessary anymore or rolling a resource back to a previous revision, effectively undoing previous changes.

Implementation

DELETING THE CURRENT REVISION

If a client attempts to delete the most recent revision, the request should fail with a 412 Precondition Failed HTTP error or equivalent.

API definition

abstract class ChatRoomApi {
 @get("/{id=chatRooms/*/messages/*}")
 GetMessage(req: GetMessageRequest): Message;

 @post("/{id=chatRooms/*/messages/*}:createRevision")
 CreateMessageRevision(req: CreateMessageRevisionRequest): Message;

 @post("/{id=chatRooms/*/messages/*}:restoreRevision")
 RestoreMessageRevision(req: RestoreMessageRevisionRequest): Message;

 @delete("/{id=chatRooms/*/messages/*}:deleteRevision")
 DeleteMessageRevision(req: DeleteMessageRevisionRequest): void;

 @get("/{id=chatRooms/*/messages/*}:listRevisions")
 ListMessageRevisions(req: ListMessageRevisionsRequest):
 ListMessageRevisionsResponse;
}


interface Message {
 id: string;
 content: string;
 // ... more fields here ...
 revisionId: string;
 revisionCreateTime: Date;
}

interface GetMessageRequest {
 id: string;
}

interface CreateMessageRevisionRequest {
 id: string;
}

interface RestoreMessageRevisionRequest {
 id: string;
 revisionId: string;
}

interface DeleteMessageRevisionRequest {
 id: string;
}

interface ListMessageRevisionsRequest {
 id: string;
 maxPageSize: number;
 pageToken: string;
}

interface ListMessageRevisionsResponse {
 results: Message[];
 nextPageToken: string;
}

Exercises

  1. What types of scenarios are a better fit for creating revisions implicitly? What about explicitly?
Example: Google Docs’ revision history, GitHub’s issue tracking.
  1. Why should revisions use random identifiers rather than incrementing numbers or timestamps?
1. Avoid leaving a gap in the revision history.
2. Avoid collisions in cases of extremely high concurrent access to the system.
  1. Why does restoration create a new revision? Why not reference a previous one?
This ensures that when we’re browsing history, we can clearly see the progression of data changes over time and not get confused with revisions being moved into different positions.
  1. What should happen if you attempt to restore a resource to a previous revision but the resource is already equivalent to that previous revision?
An entirely new revision is created.
  1. Why do we use custom method notation for listing and deleting resources rather than the standard methods?
Because we’re listing revisions that are tied to a single resource rather than child resources of a different parent.

Summary

  • Resource revisions act as snapshots of resources taken as they change over time.

  • Revisions should use random identifiers like any other resource even though it might seem to make sense to rely on something like an incrementing number or timestamp as an identifier.

  • Revisions can be created both implicitly (e.g., whenever a resource is modified) or explicitly (e.g., on request by a user).

  • Retrieving resources at specific revisions can be done by using an "@" character to indicate the revision (e.g., GET /chatRooms/1234@5678). However, both listing and deleting revisions should be done using a custom method attached to the resource in question.

  • Resources may be restored to a previous revision's state using a custom method that creates a new revision equal to the previous one and marks it as the active revision.