What is arocapi
arocapi is a library that implements the RO-Crate API specification, and part of CrateWorks. It is a Fastify plugin, so you register it in your own app, and it adds routes for listing, searching and reading the entities in a repository: collections, objects and files, each described by RO-Crate metadata.
It is built for long-term archival repositories that follow the PILARS protocols. arocapi owns the API and leaves the decisions that differ between repositories to you:
- Where things live. Entities are indexed in a database through Prisma and searched through a
search backend such as OpenSearch. A storage backend, such as the built-in
DirectoryStorageor your own, delivers RO-Crate metadata and file bytes from your storage. For now you fill the database and index yourself; support for the RO-Crate API’s deposit routes, which will let you load RO-Crates through the API, is coming soon. - Who sees what. Visibility filters decide which entities exist for a request. An access function decides whether a request may read an entity’s full metadata and its file content, usually by licence. See Visibility vs Access.
- What responses look like. Transformers can add fields to every entity and file the API returns.
Registering the plugin
Section titled “Registering the plugin”You pass everything arocapi needs as plugin options.
import { Client } from '@opensearch-project/opensearch';import { PrismaPg } from '@prisma/adapter-pg';import { AllPublicAccess, AllVisibleEntityFilter, AllVisibleSearchFilter, type Options } from 'arocapi';import { OpenSearchBackend } from 'arocapi/search/opensearch';import { DirectoryStorage } from 'arocapi/storage/directory';import { PrismaClient } from './generated/prisma/client.ts';
export const options: Options = { prisma: new PrismaClient({ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) }), search: OpenSearchBackend({ client: new Client({ node: process.env.OPENSEARCH_URL }), fields: { name: { type: 'text', weight: 2 }, description: { type: 'text' } }, }), storage: DirectoryStorage({ root: '/srv/archive' }), entityVisibilityFilter: AllVisibleEntityFilter, searchVisibilityFilter: AllVisibleSearchFilter, access: AllPublicAccess,};Every option is described under Configuration: data sources, visibility, access, storage, search, transformers and HTTP. The routes it adds are listed under Routes.
How a request is handled
Section titled “How a request is handled”Every request passes the same checks in the same order, and your code runs at each step. The request lifecycle covers it in detail. An entity Hidden from a request doesn’t exist as far as that request is concerned. Its Record appears in listings, search and entity responses whenever it is Visible, but reading its Metadata or a file’s Content also needs access. Record, Metadata, Content describes these levels, and Visibility vs Access shows what each route returns.
flowchart LR
request[Request] --> visible{Visible?}
visible -- no --> notFound[404, or 401 to prompt a login]
visible -- yes --> route{Route}
route -- listing, search or entity --> transformers[Your transformers]
transformers --> record[Record with its access]
route -- metadata or file --> accessible{Accessible?}
accessible -- no --> refused[401 or 403]
accessible -- yes --> storage[Your storage backend]
storage --> bytes[Metadata or file content]
To set up your own, start with Install.