api: /api/version + OpenAPI 3.x spec generated in code
lib/openapi.ts is the machine-readable spec (served at /api/openapi) per AGENTS.md; info.version sourced from package.json. Unit tests pin the spec shape and version sync.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
import { openApiSpec } from '@/lib/openapi';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
return Response.json(openApiSpec);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import pkg from '@/package.json';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
return Response.json({ version: pkg.version });
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import pkg from '@/package.json';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { openApiSpec } from './openapi';
|
||||||
|
|
||||||
|
describe('OpenAPI spec', () => {
|
||||||
|
it('documents exactly the one public endpoint (scaffold stage)', () => {
|
||||||
|
expect(Object.keys(openApiSpec.paths).sort()).toEqual(['/api/version']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps info.version in sync with package.json', () => {
|
||||||
|
expect(openApiSpec.info.title).toBe('SpaceWanderer API');
|
||||||
|
expect(openApiSpec.info.version).toBe(pkg.version);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses an empty server url so "try it" targets the current origin', () => {
|
||||||
|
expect(openApiSpec.servers).toEqual([{ url: '' }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('describes /api/version as { version } with a string version', () => {
|
||||||
|
const schema = openApiSpec.paths['/api/version'].get.responses[200].content['application/json'].schema;
|
||||||
|
expect(schema.$ref).toBe('#/components/schemas/AppVersion');
|
||||||
|
|
||||||
|
const appVersion = openApiSpec.components.schemas.AppVersion.properties;
|
||||||
|
expect(Object.keys(appVersion)).toEqual(['version']);
|
||||||
|
expect(appVersion.version.type).toBe('string');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import pkg from '@/package.json';
|
||||||
|
|
||||||
|
// OpenAPI 3.1 document for the app's public JSON API, kept in code so it can be
|
||||||
|
// served machine-readable at /api/openapi (see AGENTS.md "## API"). Must be updated
|
||||||
|
// whenever an endpoint changes.
|
||||||
|
export const openApiSpec = {
|
||||||
|
openapi: '3.1.0',
|
||||||
|
info: {
|
||||||
|
title: 'SpaceWanderer API',
|
||||||
|
description:
|
||||||
|
'JSON API for SpaceWanderer — a single-player turn-based space adventure. Scaffold stage: app metadata only; game endpoints (turn actions, state snapshots) land with the first game systems.',
|
||||||
|
// Sourced from package.json so it stays in sync with every version bump.
|
||||||
|
version: pkg.version,
|
||||||
|
},
|
||||||
|
// Empty url = current origin (the spec is served from the same host that runs the API).
|
||||||
|
servers: [{ url: '' }],
|
||||||
|
paths: {
|
||||||
|
'/api/version': {
|
||||||
|
get: {
|
||||||
|
summary: 'App version',
|
||||||
|
description: 'The running app version, read from package.json.',
|
||||||
|
operationId: 'getVersion',
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: 'Current app version',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: { $ref: '#/components/schemas/AppVersion' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
AppVersion: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
version: { type: 'string', description: 'Semver of the running build' },
|
||||||
|
},
|
||||||
|
required: ['version'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user