Skip to content

Commit

Permalink
Expose collection metadata in collection-api
Browse files Browse the repository at this point in the history
  • Loading branch information
Ndpnt committed Dec 3, 2024
1 parent 6190a3c commit 641ba8d
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 1 deletion.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"https-proxy-agent": "^5.0.0",
"iconv-lite": "^0.6.3",
"joplin-turndown-plugin-gfm": "^1.0.12",
"js-yaml": "^4.1.0",
"jsdom": "^18.1.0",
"json-source-map": "^0.6.1",
"lodash": "^4.17.21",
Expand Down
1 change: 1 addition & 0 deletions src/collection-api/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default async function apiRouter(basePath) {

const services = await Services.load();

router.use(await metadataRouter(services));
router.use(servicesRouter(services));
router.use(versionsRouter);

Expand Down
163 changes: 163 additions & 0 deletions src/collection-api/routes/metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import fs from 'fs/promises';
import path from 'path';

import config from 'config';
import express from 'express';
import yaml from 'js-yaml';

import Service from '../../archivist/services/service.js';

/**
* @swagger
* tags:
* name: Metadata
* description: Collection metadata API
* components:
* schemas:
* Metadata:
* type: object
* description: Collection metadata
* properties:
* id:
* type: string
* description: Unique identifier of the collection
* name:
* type: string
* description: Display name of the collection
* tagline:
* type: string
* description: Short description of the collection
* description:
* type: string
* nullable: true
* description: Detailed description of the collection
* totalTerms:
* type: integer
* description: Total number of terms tracked in the collection
* totalServices:
* type: integer
* description: Total number of services tracked in the collection
* engineVersion:
* type: string
* description: Version of the Open Terms Archive engine in SemVer format (MAJOR.MINOR.PATCH)
* dataset:
* type: string
* format: uri
* description: URL to the dataset releases
* declarations:
* type: string
* format: uri
* description: URL to the declarations repository
* versions:
* type: string
* format: uri
* description: URL to the versions repository
* snapshots:
* type: string
* format: uri
* description: URL to the snapshots repository
* logo:
* type: string
* format: uri
* nullable: true
* description: URL to the collection logo
* languages:
* type: array
* items:
* type: string
* description: List of ISO 639 language codes representing languages allowed by the collection
* jurisdictions:
* type: array
* items:
* type: string
* description: List of ISO 3166-2 country codes representing jurisdictions covered by the collection
* trackingPeriods:
* type: array
* items:
* type: object
* properties:
* startDate:
* type: string
* format: date
* description: The date when tracking started for this period
* schedule:
* type: string
* description: A cron expression defining when terms are tracked (e.g. "0 0 * * *" for daily at midnight)
* serverLocation:
* type: string
* description: The geographic location of the server used for tracking
* endDate:
* type: string
* format: date
* description: The date when tracking ended for this period
* governance:
* type: object
* properties:
* hosts:
* type: array
* items:
* $ref: '#/components/schemas/Organization'
* administrators:
* type: array
* items:
* $ref: '#/components/schemas/Organization'
* curators:
* type: array
* items:
* $ref: '#/components/schemas/Organization'
* maintainers:
* type: array
* items:
* $ref: '#/components/schemas/Organization'
* sponsors:
* type: array
* items:
* $ref: '#/components/schemas/Organization'
* Organization:
* type: object
* properties:
* name:
* type: string
* description: Name of the organization
* url:
* type: string
* format: uri
* description: URL to the organization's website
* logo:
* type: string
* format: uri
* description: URL to the organization's logo
*/
export default async function metadataRouter(services) {
const router = express.Router();
const collectionPath = path.resolve(process.cwd(), config.get('@opentermsarchive/engine.collectionPath'));
const STATIC_METADATA = yaml.load(await fs.readFile(path.join(collectionPath, '/metadata.yml'), 'utf8'));
const { version: engineVersion } = JSON.parse(await fs.readFile(new URL('../../../package.json', import.meta.url)));

/**
* @swagger
* /metadata:
* get:
* summary: Get collection metadata
* tags: [Metadata]
* produces:
* - application/json
* responses:
* 200:
* description: Collection metadata
*/
router.get('/metadata', (req, res) => {
const dynamicMetadata = {
totalServices: Object.keys(services).length,
totalTerms: Service.getNumberOfTerms(services),
engineVersion,
};

res.json({
...dynamicMetadata,
...STATIC_METADATA,
});
});

return router;
}
89 changes: 89 additions & 0 deletions src/collection-api/routes/metadata.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import fs from 'fs/promises';

import { expect } from 'chai';
import config from 'config';
import request from 'supertest';

import app from '../server.js';

const basePath = config.get('@opentermsarchive/engine.collection-api.basePath');
const { version: engineVersion } = JSON.parse(await fs.readFile(new URL('../../../package.json', import.meta.url)));

const EXPECTED_RESPONSE = {
totalServices: 7,
totalTerms: 8,
id: 'test',
name: 'test',
tagline: 'Test collection',
description: 'This is a test collection used for testing purposes.',
dataset: 'https://github.com/OpenTermsArchive/test-versions/releases',
declarations: 'https://github.com/OpenTermsArchive/test-declarations',
versions: 'https://github.com/OpenTermsArchive/test-versions',
snapshots: 'https://github.com/OpenTermsArchive/test-snapshots',
donations: null,
logo: 'https://opentermsarchive.org/images/logo/logo-open-terms-archive-black.png',
languages: [
'en',
],
jurisdictions: [
'EU',
],
governance: {
hosts: [
{ name: 'Localhost' },
],
administrators: [
{
name: 'Open Terms Archive',
url: 'https://opentermsarchive.org/',
logo: 'https://opentermsarchive.org/images/logo/logo-open-terms-archive-black.png',
},
],
curators: [
{
name: 'Open Terms Archive',
url: 'https://opentermsarchive.org/',
logo: 'https://opentermsarchive.org/images/logo/logo-open-terms-archive-black.png',
},
],
maintainers: [
{
name: 'Open Terms Archive',
url: 'https://opentermsarchive.org/',
logo: 'https://opentermsarchive.org/images/logo/logo-open-terms-archive-black.png',
},
],
sponsors: [
{
name: 'Open Terms Archive',
url: 'https://opentermsarchive.org/',
logo: 'https://opentermsarchive.org/images/logo/logo-open-terms-archive-black.png',
},
],
},
};

describe('Metadata API', () => {
describe('GET /metadata', () => {
let response;

before(async () => {
response = await request(app).get(`${basePath}/v1/metadata`);
});

it('responds with 200 status code', () => {
expect(response.status).to.equal(200);
});

it('responds with Content-Type application/json', () => {
expect(response.type).to.equal('application/json');
});

it('returns expected metadata object', () => {
expect(response.body).to.deep.equal({
...EXPECTED_RESPONSE,
engineVersion,
});
});
});
});
2 changes: 1 addition & 1 deletion test/test-declarations/metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jurisdictions:
- EU
governance:
hosts:
- name: Computer test
- name: Localhost
administrators:
- name: Open Terms Archive
url: https://opentermsarchive.org/
Expand Down

0 comments on commit 641ba8d

Please sign in to comment.