Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions apps/api/openapi/lib/openapi.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
providerIdParam():: self.stringParam('providerId', 'ID of the resource provider'),
relationshipRuleIdParam():: self.stringParam('relationshipRuleId', 'ID of the relationship rule'),

limitParam(defaultValue = 50):: {
limitParam(defaultValue=50):: {
name: 'limit',
'in': 'query',
required: false,
Expand All @@ -37,7 +37,7 @@
default: defaultValue,
},
},

offsetParam():: {
name: 'offset',
'in': 'query',
Expand All @@ -59,16 +59,16 @@
type: 'string',
},
},

// Response helpers
schemaRef(name, nullable = false):: (
schemaRef(name, nullable=false):: (
if nullable then
{ '$ref': '#/components/schemas/' + name, nullable: true }
else
{ '$ref': '#/components/schemas/' + name }
),
okResponse(schema, description = "OK response"):: {

okResponse(schema, description='OK response'):: {
'200': {
description: description,
content: {
Expand All @@ -78,8 +78,8 @@
},
},
},
acceptedResponse(schema, description = "Accepted response"):: {

acceptedResponse(schema, description='Accepted response'):: {
'202': {
description: description,
content: {
Expand All @@ -90,7 +90,7 @@
},
},

createdResponse(schema, description = "Resource created successfully"):: {
createdResponse(schema, description='Resource created successfully'):: {
'201': {
description: description,
content: {
Expand All @@ -101,6 +101,12 @@
},
},

noContent():: {
'204': {
description: 'No content',
},
},

notFoundResponse():: {
'404': {
description: 'Resource not found',
Expand All @@ -111,7 +117,7 @@
},
},
},

badRequestResponse():: {
'400': {
description: 'Invalid request',
Expand All @@ -123,7 +129,18 @@
},
},

paginatedResponse(itemsSchema, description = "Paginated list of items"):: {
internalServerError():: {
'500': {
description: 'Internal server error',
content: {
'application/json': {
schema: { '$ref': '#/components/schemas/ErrorResponse' },
},
},
},
},

paginatedResponse(itemsSchema, description='Paginated list of items'):: {
'200': {
description: description,
content: {
Expand Down
53 changes: 53 additions & 0 deletions apps/api/openapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -5647,6 +5647,59 @@
}
},
"/v1/workspaces/{workspaceId}/resources/identifier/{identifier}": {
"delete": {
"description": "Deletes a resource by its identifier.",
"operationId": "deleteResourceByIdentifier",
"parameters": [
{
"description": "ID of the workspace",
"in": "path",
"name": "workspaceId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "Identifier of the resource",
"in": "path",
"name": "identifier",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"204": {
"description": "No content"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Invalid request"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Resource not found"
}
},
"summary": "Delete resource by identifier",
"tags": [
"Resources"
]
},
"get": {
"description": "Returns a resource by its identifier.",
"operationId": "getResourceByIdentifier",
Expand Down
21 changes: 16 additions & 5 deletions apps/api/openapi/paths/resources.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ local openapi = import '../lib/openapi.libsonnet';
],
responses: openapi.okResponse(openapi.schemaRef('Resource')),
},
delete: {
tags: ['Resources'],
summary: 'Delete resource by identifier',
operationId: 'deleteResourceByIdentifier',
description: 'Deletes a resource by its identifier.',
parameters: [
openapi.workspaceIdParam(),
openapi.identifierParam(),
],
responses: openapi.noContent() + openapi.notFoundResponse() + openapi.badRequestResponse(),
},
},
'/v1/workspaces/{workspaceId}/resources/identifier/{identifier}/variables': {
get: {
Expand All @@ -42,9 +53,9 @@ local openapi = import '../lib/openapi.libsonnet';
openapi.limitParam(),
openapi.offsetParam(),
],
responses: openapi.paginatedResponse(openapi.schemaRef('ResourceVariable'), 'The requested variables') +
openapi.notFoundResponse() +
openapi.badRequestResponse(),
responses: openapi.paginatedResponse(openapi.schemaRef('ResourceVariable'), 'The requested variables') +
openapi.notFoundResponse() +
openapi.badRequestResponse(),
},
patch: {
tags: ['Resources'],
Expand Down Expand Up @@ -87,8 +98,8 @@ local openapi = import '../lib/openapi.libsonnet';
openapi.deploymentIdParam(),
],
responses: openapi.okResponse(openapi.schemaRef('ReleaseTarget'), 'The requested release target') +
openapi.notFoundResponse() +
openapi.badRequestResponse(),
openapi.notFoundResponse() +
openapi.badRequestResponse(),
},
},
}
36 changes: 36 additions & 0 deletions apps/api/src/routes/v1/workspaces/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,41 @@ const getResourceByIdentifier: AsyncTypedHandler<
res.status(200).json(result.data);
};

const deleteResourceByIdentifier: AsyncTypedHandler<
"/v1/workspaces/{workspaceId}/resources/identifier/{identifier}",
"delete"
> = async (req, res) => {
const { workspaceId, identifier } = req.params;

const resourceIdentifier = encodeURIComponent(identifier);
const resourceResponse = await getClientFor(workspaceId).GET(
"/v1/workspaces/{workspaceId}/resources/{resourceIdentifier}",
{ params: { path: { workspaceId, resourceIdentifier } } },
);
if (resourceResponse.error != null) {
const status = resourceResponse.response.status;
if (status >= 500) {
throw new ApiError(
resourceResponse.error.error ?? "Internal server error",
status,
);
}
throw new ApiError(
resourceResponse.error.error ?? "Resource not found",
status,
);
}

await sendGoEvent({
workspaceId,
eventType: Event.ResourceDeleted,
timestamp: Date.now(),
data: resourceResponse.data,
});

res.status(204).end();
};

const getVariablesForResource: AsyncTypedHandler<
"/v1/workspaces/{workspaceId}/resources/identifier/{identifier}/variables",
"get"
Expand Down Expand Up @@ -147,6 +182,7 @@ const getReleaseTargetForResourceInDeployment: AsyncTypedHandler<
export const resourceRouter = Router({ mergeParams: true })
.get("/", asyncHandler(listResources))
.get("/identifier/:identifier", asyncHandler(getResourceByIdentifier))
.delete("/identifier/:identifier", asyncHandler(deleteResourceByIdentifier))
.get(
"/identifier/:identifier/variables",
asyncHandler(getVariablesForResource),
Expand Down
47 changes: 46 additions & 1 deletion apps/api/src/types/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,11 @@ export interface paths {
get: operations["getResourceByIdentifier"];
put?: never;
post?: never;
delete?: never;
/**
* Delete resource by identifier
* @description Deletes a resource by its identifier.
*/
delete: operations["deleteResourceByIdentifier"];
options?: never;
head?: never;
patch?: never;
Expand Down Expand Up @@ -3754,6 +3758,47 @@ export interface operations {
};
};
};
deleteResourceByIdentifier: {
parameters: {
query?: never;
header?: never;
path: {
/** @description ID of the workspace */
workspaceId: string;
/** @description Identifier of the resource */
identifier: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description No content */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Invalid request */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorResponse"];
};
};
/** @description Resource not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorResponse"];
};
};
};
};
getVariablesForResource: {
parameters: {
query?: {
Expand Down
Loading