diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 926d8d66f..02f13d3a9 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -693,6 +693,14 @@ export interface IEndpointMeta { * @example (v0) /api/notes/create -> /api/v2/notes */ readonly alias?: string; + + /** + * If any path parameters were used, they have to be listed here. + * Otherwise they will show up as query parameters in the documentation. + * + * Note: Path parameters cannot be optional. + */ + readonly pathParamers?: string[]; }; } diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 091bab766..db270af3a 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -25,6 +25,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/children', + pathParameters: ['noteId'], }, } as const; diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index 3cd878800..e87daedcf 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -22,6 +22,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/clips', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index 7e736c736..3ea80f860 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -22,6 +22,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/conversation', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index f49faafaf..83f768c37 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -22,6 +22,7 @@ export const meta = { v2: { method: 'delete', alias: 'notes/:noteId', + pathParameters: ['noteId'], }, errors: ['ACCESS_DENIED', 'NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 6fd0e8f16..2b73a381d 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -25,7 +25,8 @@ export const meta = { v2: { method: 'get', - alias: 'notes/:noteId/reactions/:type?', + alias: 'notes/:noteId/reactions', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index 55674f9ee..af02aa15c 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -25,6 +25,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/renotes', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index 34b679ae4..e3bb33047 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -25,6 +25,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/replies', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 6c3f68407..9f3c68f32 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -17,6 +17,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index c578e1419..a98903177 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -30,6 +30,7 @@ export const meta = { v2: { method: 'get', alias: 'notes/:noteId/status', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 1c4989354..e366f84dd 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -57,7 +57,8 @@ export const meta = { v2: { method: 'get', - alias: 'notes/:noteId/translate/:targetLang/:sourceLang?', + alias: 'notes/:noteId/translate/:targetLang', + pathParameters: ['noteId', 'targetLang'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index 71ff2a0c4..446a14981 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -22,6 +22,7 @@ export const meta = { v2: { method: 'delete', alias: 'notes/:noteId/renotes', + pathParameters: ['noteId'], }, errors: ['NO_SUCH_NOTE'], diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 04003097c..ece0bef24 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -126,10 +126,10 @@ export function genOpenapiSpec() { }; } - let desc = endpoint.meta.description ?? 'No description provided.'); + let desc = endpoint.meta.description ?? 'No description provided.'; desc += `**Credential required**: *${endpoint.meta.requireCredential ? 'Yes' : 'No'}*`; if (endpoint.meta.kind) { - desc += `\n\n**Permission**: `' + endpoint.meta.kind + '`'; + desc += '\n\n**Permission**: `' + endpoint.meta.kind + '`'; } if (endpoint.meta.limit) { const limit = endpoint.meta.limit; @@ -220,11 +220,37 @@ export function genOpenapiSpec() { spec.paths['/' + endpoint.name] = path; if (endpoint.meta.v2) { + const route = `/v2/${endpoint.meta.v2.alias ?? endpoint.name.replace(/-/g, '_')}`; // we need a clone of the API endpoint info because otherwise we change it by reference const infoClone = structuredClone(info); - const route = `/v2/${endpoint.meta.v2.alias ?? endpoint.name.replace(/-/g, '_')}`; + // fix the way parameters are passed + const hasBody = !(endpoint.meta.v2.method === 'get' || endpoint.meta.v2.method === 'delete'); + if (!hasBody) { + // these methods do not (usually) have a body + delete infoClone.requestBody; + infoClone.parameters = []; + for (const name in schema.properties) { + infoClone.parameters.push({ + name, + in: endpoint.meta.v2?.pathParameters?.includes(name) ? 'path' : 'query', + schema: schema.properties[name], + required: endpoint.meta.v2?.pathParameters?.includes(name) || schema.required?.includes(name) || false, + }); + } + } else if (endpoint.meta.v2.pathParameters) { + for (const name in endpoint.meta.v2.pathParameters) { + delete infoClone.requestBody.content[requestType].schema.properties[name]; + infoClone.parameters.push({ + name, + in: 'path', + schema: schema.properties[name], + required: true, + }); + } + } - infoClone['operationId'] = infoClone['summary'] = route; + infoClone['operationId'] = endpoint.meta.v2.method.toUpperCase() + '/' + route; + infoClone['summary'] = endpoint.meta.v2.method.toUpperCase() + ' ' + route; spec.paths[route] = { ...spec.paths[route],