Restore
ids is always an array, even for a single record. Undoes a soft-delete — deletedAt goes back to null. A record that was never deleted, or one you don’t have delete on, answers error for that entry the same way any other capability check does — see Errors and responses. One record failing never blocks the others in the same request.
POST /blog-posts/restore
Authorization: Bearer <token>
Content-Type: application/json
{
"ids": [
"cxmpl00000000000000000023"
]
}Body fields
Section titled “Body fields”| Field | Type | What it does |
|---|---|---|
ids |
array | The records to restore |
patch |
object | Optional — see below |
Restoring with a patch
Section titled “Restoring with a patch”An optional patch reapplies a short, scoped update in the same call, reusing the resource’s own update field whitelist rather than a second round trip (see the “Restaurer avec un correctif” scenario above).
The real generated handler, from examples/blog-post/blog-post.controller.ts:
@Post('restore')
@Capability(canRestoreAnyBlogPost)
async restore(
@Req() req: RequestWithUser,
@Body(new ZodValidationPipe(restoreBlogPostRequestSchema))
body: RestoreBlogPostRequestBody,
) {
const subject = subjectOf(req.user);
const loaded = await this.loadAndAuthorize(body.ids, subject, (s, record) =>
canRestoreBlogPost(s, record as never),
);
const entries = loaded.map((entry, index): BatchEntry<BlogPostView> => {
if (!entry.ok) {
return { index, id: entry.id, failure: entry.error };
}
return {
index,
id: entry.id,
run: async () => {
if (!entry.record.deletedAt) {
throw new AlreadyRestoredException('blog-post');
}
return toBlogPostView(
await this.blogPosts.restore(entry.record, body.patch),
);
},
};
});
const { results, meta } = await this.runBatch(entries, body.atomic);
return ok(results, meta);
}