@dandi/mvc-hal v1.0.0-alpha.77
@dandi/mvc-hal
@dandi/mvc-hal provides services for emitting
HAL JSON
(application/hal+json) from @dandi/mvc controllers.
Usage
To use the HAL services from @dandi/mvc-hal, add the MvcHalModule to
your server container.
HalResultTransformerwill intercept the value returned by controller methods and attempt to compose it into a HAL resource.DefaultResourceComposeris the default composer used byHalResultTransformer, and will automatically add a link for theselfrelation, add any other relations specified by the@Relation()or@ListRelation()decorators, and embed any relations specified on the request by the_embeddedquerystring param.
Decorators
Relations between resources, as well as resource identifiers, are defined using decorators.
Defining a Resource
Use @ResourceId() to define the identifier property on a resource:
export class TaskList {
@ResourceId()
@Property(Uuid)
@Required()
public listId: Uuid
}The @ResourceId() decorator on the resource model must correspond with
a @ResourceAccessor() decorator, which is applied to the controller
method used to get that resource, and a @AccessorResourceId()
decorator on the parameter specifying the source for model's ID:
@Controller('/list')
export class TaskListController {
@HttpGet(':listId')
@ResourceAccessor(TaskList)
public getList(@PathParam(Uuid) @AccessorResourceId() listId: Uuid): Promise<TaskList> {
...
}
}The @AccessorResourceId() decorator on the listId parameter will be linked
to the listId property on the TaskList model since the
@ResourceAccessor() decorator specifies TaskList as its type, and
listId is defined as its ID property by its own @ResourceId()
decorator.
Controller methods that list a resource can be identified using the
@ResourceListAccessor() decorator:
@Controller('/list')
export class TaskListController {
@HttpGet(':listId')
@ResourceAccessor(TaskList)
public getList(@PathParam(Uuid) @AccessorResourceId() listId: Uuid): Promise<TaskList> {
...
}
@HttpGet()
@ResourceListAccessor(TaskList)
public getAllLists(): Promise<TaskList[]> {
...
}
}The combination of these decorators enables the resource composer to
correctly and automatically generate the self relation link.
Defining Resource Relations
The @ResourceId() decorator can also be used in correlation with
@Relation to define relations of a resource.
export class Task {
@Property(Uuid)
@Required()
@ResourceId()
public taskId: Uuid
@Property(Uuid)
@Required()
@ResourceId(List, 'list')
public listId: Uuid
@Relation(List)
public list?: List
}The @Relation() decorator on the list property marks that property
as a relation. The @ResourceId() decorator on the listId property
describes that property as the identifier for the aforementioned list
relation. Assuming a TaskController implementation with a
corresponding @ResourceAccessor for the Task resource, these
decorators will allow the resource composer to automatically generate
links or embed resources for the list relation of a task.
Avoiding Circular References with Circular Relations
Using the example of a task list, we will probably want the following relations:
Taskhaslistrelation to theTaskListit belongs toTaskListhas atasksrelation to the array ofTaskresources that belong to it
Attempting to do this with one model per resource will result in unresolvable circular dependency issues. One way to work around this is to define the relations in separate models:
export class TaskList {
@ResourceId()
@Property(Uuid)
@Required()
public listId: Uuid;
}
export class Task {
@Property(Uuid)
@Required()
@ResourceId()
public taskId: Uuid;
@Property(Uuid)
@Required()
@ResourceId(List, 'list')
public listId: Uuid;
}
export class TaskListResource extends TaskList {
@ListRelation(Task)
public tasks: Task[];
}
export class TaskResource extends Task {
@Relation(List)
public list?: List;
}
@Controller('/list')
export class TaskListController {
@HttpGet(':listId')
@ResourceAccessor(TaskListResource)
public getList(@PathParam(Uuid) @AccessorResourceId() listId: Uuid): Promise<TaskList> {
...
}
@HttpGet(':listId/task')
@ResourceListAccessor(Task)
public listTasks(@PathParam(Uuid) @AccessorResourceId(List) listId: Uuid): Promise<Task[]> {
...
}
}
@Controller('/task')
export class TaskListController {
@HttpGet(':taskId')
@ResourceAccessor(TaskResource)
public getTask(@PathParam(Uuid) @AccessorResourceId() listId: Uuid): Promise<Task> {
...
}
}4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago