/v1/id/_:id/expanded endpoint - #286
Draft
thehabes wants to merge 9 commits into
Draft
Conversation
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #285.
Summary
Adds
GETandPOST /v1/id/:_id/expanded— a generic, unauthenticated, browser-cacheable endpoint that returns a RERUM object with the assertions of every current Annotation targeting it already merged in.Changes
New endpoint
routes/id.js—/:_id/expandedregistered ahead of/:_id.GET,POST(behindrest.verifyJsonContentType), andHEADvia Express's nativeGEThandling. Everything else is a405.controllers/crud.js—idExpanded()plus three helpers:sanitizeExpansionFilters()reduces a POST body to the filter keys this endpoint will honor.assertionsFrom()reads onlybodyandbodyValueoff an Annotation, so no other property of an Annotation can leak onto the entity.applyRawExpansion()merges those assertions onto a clone of the entity and re-appends__rerumlast.db-controller.js— exportsidExpanded.GET— the convenience formImagined as the plain
GETwhere nothing else is supplied. Recognizes?generator=and?creator=only, both matched across thehttp/httpsspellings of the URI.?limit=(default 200) and?skip=page the Annotation search.POST— the filtered formThe JSON body is an object of literal MongoDB filter keys,
ANDed into the Annotation search — so filtering by generating app means supplying the real property name,__rerum.generatedBy. URL parameters supply no filters here, though?limit=and?skip=still page. Not browser-cached.Because every supplied filter is
ANDed in, a filter can only narrow the result set — there is no way to widen it past the entity in the request URI.Response headers
Cache-Control: max-age=86400, must-revalidate— only on theGET, so browsers can cache for 24h. Annotations on an entity are volatile during initial creation and stable afterward, so this trades a hard reload in the rare stale case for not re-running the expand on every visit.Annotations-Gathered— the size of the page you received. When it equals yourlimitthere may be more, and you were expanded from only part of the record's Annotations. This is the one to page off.Annotations-Merged— how many of those could contribute. Annotations with multiple bodies are not counted. A counted Annotation may still assert nothing mergeable, so this is not a count of properties received either.Locationis canonicalized to the_idform, so a slug request advertises the stable URL.controllers/gog.jsRefactored onto the shared helper, which is where the bulk of the deletions come from. Three behavior changes ride along, all on
/gog/id/:_id:hasOwnProperty→Object.hasOwn. An Annotation body assertinghasOwnPropertywould otherwise shadow the method and break the merge. This one is load-bearing, not cosmetic./gog/id/:_idis now restricted to GoG-generated data (403otherwise), and expands only with Annotations from the entity's own generator.Measured against production before merging: across 3,000 sampled leaf entities generated by a GoG agent, all 24,259 leaf Annotations targeting them are from the GoG production agent, so the generator filter drops nothing today. The prod/dev agent ids moved into named constants at the top of the file.
Documentation
public/API.htmlgets both forms underGETandPOST, including the full merge rules and the ignored-filters table.openapi/contracts/core-provider.openapi.yamlgets/id/{id}/expandedwithget,head, andpost.Testing
No tests have been written for the new endpoint yet, this is TODO