api+openapi: GET /api/ship + POST upgrade/expand/build with 400/404/409/422 mapping
This commit is contained in:
@@ -8,12 +8,37 @@ describe('OpenAPI spec', () => {
|
||||
'/api/crew',
|
||||
'/api/explore',
|
||||
'/api/jump',
|
||||
'/api/ship',
|
||||
'/api/ship/build',
|
||||
'/api/ship/expand',
|
||||
'/api/ship/upgrade',
|
||||
'/api/system',
|
||||
'/api/version',
|
||||
'/api/world',
|
||||
]);
|
||||
});
|
||||
|
||||
it('describes the ship endpoints as ShipState in and out, with error responses on the actions', () => {
|
||||
const ship = openApiSpec.paths['/api/ship'].get.responses[200].content['application/json'].schema;
|
||||
expect(ship.$ref).toBe('#/components/schemas/ShipState');
|
||||
|
||||
const system = openApiSpec.components.schemas.ShipSystem.properties;
|
||||
expect(Object.keys(system)).toEqual(['id', 'type', 'level', 'capacity', 'built']);
|
||||
|
||||
for (const [path, request] of [
|
||||
['/api/ship/upgrade', '#/components/schemas/UpgradeRequest'],
|
||||
['/api/ship/expand', '#/components/schemas/ExpandRequest'],
|
||||
['/api/ship/build', '#/components/schemas/BuildRequest'],
|
||||
] as const) {
|
||||
const post = openApiSpec.paths[path].post;
|
||||
expect(post.requestBody.content['application/json'].schema.$ref).toBe(request);
|
||||
expect(post.responses[200].content['application/json'].schema.$ref).toBe('#/components/schemas/ShipState');
|
||||
for (const status of ['400', '404', '409', '422'] as const) {
|
||||
expect(post.responses[status].content['application/json'].schema.$ref).toBe('#/components/schemas/Error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('describes /api/crew as an array of CrewMember and crewFound on ExploreResult', () => {
|
||||
const crew = openApiSpec.paths['/api/crew'].get.responses[200].content['application/json'].schema;
|
||||
expect(crew.type).toBe('array');
|
||||
|
||||
+237
@@ -186,6 +186,198 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/ship': {
|
||||
get: {
|
||||
summary: 'Ship state',
|
||||
description:
|
||||
"The ship's systems (built flag derived from level), the cargo hold and the turn counter. The starting ship is seeded on new game — core types built at base values, the rest unbuilt until a build action. Auto-initializes a new game when no save exists yet.",
|
||||
operationId: 'getShip',
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Current ship state',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ShipState' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/ship/upgrade': {
|
||||
post: {
|
||||
summary: 'Upgrade a ship system',
|
||||
description:
|
||||
"Level up a built ship system by one (capped at max level). Costs `level` units of any resource, consumed from the oldest cargo row first, plus a turn. Returns the fresh ship state.",
|
||||
operationId: 'upgradeShipSystem',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/UpgradeRequest' },
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Fresh ship state after the upgrade',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ShipState' },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: 'Malformed body or non-integer systemId',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: 'Unknown ship system id',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: 'System is not built or already at max level',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
422: {
|
||||
description: 'Not enough resources in the cargo hold for the cost',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/ship/expand': {
|
||||
post: {
|
||||
summary: 'Expand a ship system',
|
||||
description:
|
||||
"Raise a built ship system's capacity by one (capped at max capacity). Costs `capacity` units of any resource, consumed from the oldest cargo row first, plus a turn. Returns the fresh ship state.",
|
||||
operationId: 'expandShipSystem',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ExpandRequest' },
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Fresh ship state after the expansion',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ShipState' },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: 'Malformed body or non-integer systemId',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: 'Unknown ship system id',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: 'System is not built or already at max capacity',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
422: {
|
||||
description: 'Not enough resources in the cargo hold for the cost',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/ship/build': {
|
||||
post: {
|
||||
summary: 'Build a ship system',
|
||||
description:
|
||||
'Build an unbuilt ship system type at base values. Costs a flat amount of parts, consumed from the oldest cargo row first, plus a turn. Returns the fresh ship state.',
|
||||
operationId: 'buildShipSystem',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/BuildRequest' },
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Fresh ship state after the build',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ShipState' },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: 'Malformed body or empty type',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: 'Unknown ship system type',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: 'System is already built',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
422: {
|
||||
description: 'Not enough parts in the cargo hold for the cost',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
schemas: {
|
||||
@@ -275,6 +467,51 @@ export const openApiSpec = {
|
||||
},
|
||||
required: ['id', 'name', 'role', 'trait_good', 'trait_bad', 'origin'],
|
||||
},
|
||||
ShipSystem: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
type: { type: 'string', description: "System type, e.g. REACTOR or WEAPONS" },
|
||||
level: { type: 'integer', description: '0 when not built yet' },
|
||||
capacity: { type: 'integer', description: '0 when not built yet' },
|
||||
built: { type: 'boolean', description: 'Derived — true when level > 0' },
|
||||
},
|
||||
required: ['id', 'type', 'level', 'capacity', 'built'],
|
||||
},
|
||||
ShipState: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
systems: {
|
||||
type: 'array',
|
||||
description: "The ship's systems in display order",
|
||||
items: { $ref: '#/components/schemas/ShipSystem' },
|
||||
},
|
||||
inventory: { type: 'array', items: { $ref: '#/components/schemas/InventoryItem' } },
|
||||
turn: { type: 'integer', description: 'Turn counter — one per jump, exploration or ship action' },
|
||||
},
|
||||
required: ['systems', 'inventory', 'turn'],
|
||||
},
|
||||
UpgradeRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
systemId: { type: 'integer', description: 'ship_systems.id of the built system to level up' },
|
||||
},
|
||||
required: ['systemId'],
|
||||
},
|
||||
ExpandRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
systemId: { type: 'integer', description: 'ship_systems.id of the built system to expand' },
|
||||
},
|
||||
required: ['systemId'],
|
||||
},
|
||||
BuildRequest: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: { type: 'string', description: "Ship system type to build, e.g. WEAPONS (see ShipSystem.type)" },
|
||||
},
|
||||
required: ['type'],
|
||||
},
|
||||
SystemState: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
Reference in New Issue
Block a user