diff --git a/workspaces/backend/api/app.go b/workspaces/backend/api/app.go index e533eac8..0500e70f 100644 --- a/workspaces/backend/api/app.go +++ b/workspaces/backend/api/app.go @@ -113,8 +113,8 @@ func (a *App) Routes() http.Handler { router.GET(AllNamespacesPath, a.GetNamespacesHandler) // workspaces - router.GET(AllWorkspacesPath, a.GetWorkspacesHandler) - router.GET(WorkspacesByNamespacePath, a.GetWorkspacesHandler) + router.GET(AllWorkspacesPath, a.GetAllWorkspacesHandler) + router.GET(WorkspacesByNamespacePath, a.GetWorkspacesByNamespaceHandler) router.GET(WorkspacesByNamePath, a.GetWorkspaceHandler) router.POST(WorkspacesByNamespacePath, a.CreateWorkspaceHandler) router.DELETE(WorkspacesByNamePath, a.DeleteWorkspaceHandler) diff --git a/workspaces/backend/api/healthcheck_handler.go b/workspaces/backend/api/healthcheck_handler.go index 69a1b78a..cdd7ff88 100644 --- a/workspaces/backend/api/healthcheck_handler.go +++ b/workspaces/backend/api/healthcheck_handler.go @@ -29,6 +29,7 @@ import ( // @Summary Returns the health status of the application // @Description Provides a healthcheck response indicating the status of key services. // @Tags healthcheck +// @ID getHealthcheck // @Produce application/json // @Success 200 {object} health_check.HealthCheck "Successful healthcheck response" // @Failure 500 {object} ErrorEnvelope "Internal server error" diff --git a/workspaces/backend/api/namespaces_handler.go b/workspaces/backend/api/namespaces_handler.go index 9405c2e0..69773f2f 100644 --- a/workspaces/backend/api/namespaces_handler.go +++ b/workspaces/backend/api/namespaces_handler.go @@ -33,6 +33,7 @@ type NamespaceListEnvelope Envelope[[]models.Namespace] // @Summary Returns a list of all namespaces // @Description Provides a list of all namespaces that the user has access to // @Tags namespaces +// @ID listNamespaces // @Produce application/json // @Success 200 {object} NamespaceListEnvelope "Successful namespaces response" // @Failure 401 {object} ErrorEnvelope "Unauthorized" diff --git a/workspaces/backend/api/workspace_actions_handler.go b/workspaces/backend/api/workspace_actions_handler.go index 75e1001d..0b1f54fa 100644 --- a/workspaces/backend/api/workspace_actions_handler.go +++ b/workspaces/backend/api/workspace_actions_handler.go @@ -39,6 +39,7 @@ type WorkspaceActionPauseEnvelope Envelope[*models.WorkspaceActionPause] // @Summary Pause or unpause a workspace // @Description Pauses or unpauses a workspace, stopping or resuming all associated pods. // @Tags workspaces +// @ID updateWorkspacePauseState // @Accept json // @Produce json // @Param namespace path string true "Namespace of the workspace" extensions(x-example=default) diff --git a/workspaces/backend/api/workspacekinds_handler.go b/workspaces/backend/api/workspacekinds_handler.go index 85bd5a62..b995a400 100644 --- a/workspaces/backend/api/workspacekinds_handler.go +++ b/workspaces/backend/api/workspacekinds_handler.go @@ -47,6 +47,7 @@ type WorkspaceKindEnvelope Envelope[models.WorkspaceKind] // @Summary Get workspace kind // @Description Returns details of a specific workspace kind identified by its name. Workspace kinds define the available types of workspaces that can be created. // @Tags workspacekinds +// @ID getWorkspaceKind // @Accept json // @Produce json // @Param name path string true "Name of the workspace kind" extensions(x-example=jupyterlab) @@ -101,6 +102,7 @@ func (a *App) GetWorkspaceKindHandler(w http.ResponseWriter, r *http.Request, ps // @Summary List workspace kinds // @Description Returns a list of all available workspace kinds. Workspace kinds define the different types of workspaces that can be created in the system. // @Tags workspacekinds +// @ID listWorkspaceKinds // @Accept json // @Produce json // @Success 200 {object} WorkspaceKindListEnvelope "Successful operation. Returns a list of all available workspace kinds." @@ -136,6 +138,7 @@ func (a *App) GetWorkspaceKindsHandler(w http.ResponseWriter, r *http.Request, _ // @Summary Create workspace kind // @Description Creates a new workspace kind. // @Tags workspacekinds +// @ID createWorkspaceKind // @Accept application/yaml // @Produce json // @Param body body string true "Kubernetes YAML manifest of a WorkspaceKind" diff --git a/workspaces/backend/api/workspacekinds_handler_test.go b/workspaces/backend/api/workspacekinds_handler_test.go index 19853676..46465927 100644 --- a/workspaces/backend/api/workspacekinds_handler_test.go +++ b/workspaces/backend/api/workspacekinds_handler_test.go @@ -209,7 +209,7 @@ var _ = Describe("WorkspaceKinds Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetWorkspaceKindsHandler") ps := httprouter.Params{} rr := httptest.NewRecorder() a.GetWorkspaceKindsHandler(rr, req, ps) diff --git a/workspaces/backend/api/workspaces_handler.go b/workspaces/backend/api/workspaces_handler.go index 97354b12..a03f7c4a 100644 --- a/workspaces/backend/api/workspaces_handler.go +++ b/workspaces/backend/api/workspaces_handler.go @@ -44,6 +44,7 @@ type WorkspaceEnvelope Envelope[models.Workspace] // @Summary Get workspace // @Description Returns details of a specific workspace identified by namespace and workspace name. // @Tags workspaces +// @ID getWorkspace // @Accept json // @Produce json // @Param namespace path string true "Namespace of the workspace" extensions(x-example=kubeflow-user-example-com) @@ -99,24 +100,44 @@ func (a *App) GetWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps htt a.dataResponse(w, r, responseEnvelope) } -// GetWorkspacesHandler returns a list of workspaces. +// GetAllWorkspacesHandler returns a list of all workspaces across all namespaces. // -// @Summary List workspaces -// @Description Returns a list of workspaces. The endpoint supports two modes: -// @Description 1. List all workspaces across all namespaces (when no namespace is provided) -// @Description 2. List workspaces in a specific namespace (when namespace is provided) +// @Summary List all workspaces +// @Description Returns a list of all workspaces across all namespaces. // @Tags workspaces +// @ID listAllWorkspaces // @Accept json // @Produce json -// @Param namespace path string true "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces." extensions(x-example=kubeflow-user-example-com) -// @Success 200 {object} WorkspaceListEnvelope "Successful operation. Returns a list of workspaces." +// @Success 200 {object} WorkspaceListEnvelope "Successful operation. Returns a list of all workspaces." +// @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." +// @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to list workspaces." +// @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." +// @Router /workspaces [get] +func (a *App) GetAllWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + a.getWorkspacesHandler(w, r, ps) +} + +// GetWorkspacesByNamespaceHandler returns a list of workspaces in a specific namespace. +// +// @Summary List workspaces by namespace +// @Description Returns a list of workspaces in a specific namespace. +// @Tags workspaces +// @ID listWorkspacesByNamespace +// @Accept json +// @Produce json +// @Param namespace path string true "Namespace to filter workspaces" extensions(x-example=kubeflow-user-example-com) +// @Success 200 {object} WorkspaceListEnvelope "Successful operation. Returns a list of workspaces in the specified namespace." // @Failure 400 {object} ErrorEnvelope "Bad Request. Invalid namespace format." // @Failure 401 {object} ErrorEnvelope "Unauthorized. Authentication is required." // @Failure 403 {object} ErrorEnvelope "Forbidden. User does not have permission to list workspaces." // @Failure 500 {object} ErrorEnvelope "Internal server error. An unexpected error occurred on the server." -// @Router /workspaces [get] // @Router /workspaces/{namespace} [get] -func (a *App) GetWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (a *App) GetWorkspacesByNamespaceHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + a.getWorkspacesHandler(w, r, ps) +} + +// getWorkspacesHandler is the internal implementation for listing workspaces. +func (a *App) getWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { namespace := ps.ByName(NamespacePathParam) // validate path parameters @@ -167,6 +188,7 @@ func (a *App) GetWorkspacesHandler(w http.ResponseWriter, r *http.Request, ps ht // @Summary Create workspace // @Description Creates a new workspace in the specified namespace. // @Tags workspaces +// @ID createWorkspace // @Accept json // @Produce json // @Param namespace path string true "Namespace for the workspace" extensions(x-example=kubeflow-user-example-com) @@ -267,6 +289,7 @@ func (a *App) CreateWorkspaceHandler(w http.ResponseWriter, r *http.Request, ps // @Summary Delete workspace // @Description Deletes a specific workspace identified by namespace and workspace name. // @Tags workspaces +// @ID deleteWorkspace // @Accept json // @Produce json // @Param namespace path string true "Namespace of the workspace" extensions(x-example=kubeflow-user-example-com) diff --git a/workspaces/backend/api/workspaces_handler_test.go b/workspaces/backend/api/workspaces_handler_test.go index 10f1b445..23a35f67 100644 --- a/workspaces/backend/api/workspaces_handler_test.go +++ b/workspaces/backend/api/workspaces_handler_test.go @@ -164,10 +164,10 @@ var _ = Describe("Workspaces Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetAllWorkspacesHandler") ps := httprouter.Params{} rr := httptest.NewRecorder() - a.GetWorkspacesHandler(rr, req, ps) + a.GetAllWorkspacesHandler(rr, req, ps) rs := rr.Result() defer rs.Body.Close() @@ -219,12 +219,12 @@ var _ = Describe("Workspaces Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetWorkspacesByNamespaceHandler") ps := httprouter.Params{ httprouter.Param{Key: NamespacePathParam, Value: namespaceName1}, } rr := httptest.NewRecorder() - a.GetWorkspacesHandler(rr, req, ps) + a.GetWorkspacesByNamespaceHandler(rr, req, ps) rs := rr.Result() defer rs.Body.Close() @@ -429,12 +429,12 @@ var _ = Describe("Workspaces Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetWorkspacesByNamespaceHandler") ps := httprouter.Params{ httprouter.Param{Key: NamespacePathParam, Value: namespaceName1}, } rr := httptest.NewRecorder() - a.GetWorkspacesHandler(rr, req, ps) + a.GetWorkspacesByNamespaceHandler(rr, req, ps) rs := rr.Result() defer rs.Body.Close() @@ -543,10 +543,10 @@ var _ = Describe("Workspaces Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetAllWorkspacesHandler") ps := httprouter.Params{} rr := httptest.NewRecorder() - a.GetWorkspacesHandler(rr, req, ps) + a.GetAllWorkspacesHandler(rr, req, ps) rs := rr.Result() defer rs.Body.Close() @@ -577,12 +577,12 @@ var _ = Describe("Workspaces Handler", func() { By("setting the auth headers") req.Header.Set(userIdHeader, adminUser) - By("executing GetWorkspacesHandler") + By("executing GetWorkspacesByNamespaceHandler") ps := httprouter.Params{ httprouter.Param{Key: NamespacePathParam, Value: missingNamespace}, } rr := httptest.NewRecorder() - a.GetWorkspacesHandler(rr, req, ps) + a.GetWorkspacesByNamespaceHandler(rr, req, ps) rs := rr.Result() defer rs.Body.Close() diff --git a/workspaces/backend/openapi/docs.go b/workspaces/backend/openapi/docs.go index d4324874..616bb409 100644 --- a/workspaces/backend/openapi/docs.go +++ b/workspaces/backend/openapi/docs.go @@ -29,6 +29,7 @@ const docTemplate = `{ "healthcheck" ], "summary": "Returns the health status of the application", + "operationId": "getHealthcheck", "responses": { "200": { "description": "Successful healthcheck response", @@ -55,6 +56,7 @@ const docTemplate = `{ "namespaces" ], "summary": "Returns a list of all namespaces", + "operationId": "listNamespaces", "responses": { "200": { "description": "Successful namespaces response", @@ -96,6 +98,7 @@ const docTemplate = `{ "workspacekinds" ], "summary": "List workspace kinds", + "operationId": "listWorkspaceKinds", "responses": { "200": { "description": "Successful operation. Returns a list of all available workspace kinds.", @@ -135,6 +138,7 @@ const docTemplate = `{ "workspacekinds" ], "summary": "Create workspace kind", + "operationId": "createWorkspaceKind", "parameters": [ { "description": "Kubernetes YAML manifest of a WorkspaceKind", @@ -217,6 +221,7 @@ const docTemplate = `{ "workspacekinds" ], "summary": "Get workspace kind", + "operationId": "getWorkspaceKind", "parameters": [ { "type": "string", @@ -269,7 +274,7 @@ const docTemplate = `{ }, "/workspaces": { "get": { - "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "description": "Returns a list of all workspaces across all namespaces.", "consumes": [ "application/json" ], @@ -279,20 +284,15 @@ const docTemplate = `{ "tags": [ "workspaces" ], - "summary": "List workspaces", + "summary": "List all workspaces", + "operationId": "listAllWorkspaces", "responses": { "200": { - "description": "Successful operation. Returns a list of workspaces.", + "description": "Successful operation. Returns a list of all workspaces.", "schema": { "$ref": "#/definitions/api.WorkspaceListEnvelope" } }, - "400": { - "description": "Bad Request. Invalid namespace format.", - "schema": { - "$ref": "#/definitions/api.ErrorEnvelope" - } - }, "401": { "description": "Unauthorized. Authentication is required.", "schema": { @@ -316,7 +316,7 @@ const docTemplate = `{ }, "/workspaces/{namespace}": { "get": { - "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "description": "Returns a list of workspaces in a specific namespace.", "consumes": [ "application/json" ], @@ -326,12 +326,13 @@ const docTemplate = `{ "tags": [ "workspaces" ], - "summary": "List workspaces", + "summary": "List workspaces by namespace", + "operationId": "listWorkspacesByNamespace", "parameters": [ { "type": "string", "x-example": "kubeflow-user-example-com", - "description": "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces.", + "description": "Namespace to filter workspaces", "name": "namespace", "in": "path", "required": true @@ -339,7 +340,7 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "Successful operation. Returns a list of workspaces.", + "description": "Successful operation. Returns a list of workspaces in the specified namespace.", "schema": { "$ref": "#/definitions/api.WorkspaceListEnvelope" } @@ -382,6 +383,7 @@ const docTemplate = `{ "workspaces" ], "summary": "Create workspace", + "operationId": "createWorkspace", "parameters": [ { "type": "string", @@ -466,6 +468,7 @@ const docTemplate = `{ "workspaces" ], "summary": "Pause or unpause a workspace", + "operationId": "updateWorkspacePauseState", "parameters": [ { "type": "string", @@ -564,6 +567,7 @@ const docTemplate = `{ "workspaces" ], "summary": "Get workspace", + "operationId": "getWorkspace", "parameters": [ { "type": "string", @@ -633,6 +637,7 @@ const docTemplate = `{ "workspaces" ], "summary": "Delete workspace", + "operationId": "deleteWorkspace", "parameters": [ { "type": "string", diff --git a/workspaces/backend/openapi/swagger.json b/workspaces/backend/openapi/swagger.json index ff81e8bf..6260cf1b 100644 --- a/workspaces/backend/openapi/swagger.json +++ b/workspaces/backend/openapi/swagger.json @@ -27,6 +27,7 @@ "healthcheck" ], "summary": "Returns the health status of the application", + "operationId": "getHealthcheck", "responses": { "200": { "description": "Successful healthcheck response", @@ -53,6 +54,7 @@ "namespaces" ], "summary": "Returns a list of all namespaces", + "operationId": "listNamespaces", "responses": { "200": { "description": "Successful namespaces response", @@ -94,6 +96,7 @@ "workspacekinds" ], "summary": "List workspace kinds", + "operationId": "listWorkspaceKinds", "responses": { "200": { "description": "Successful operation. Returns a list of all available workspace kinds.", @@ -133,6 +136,7 @@ "workspacekinds" ], "summary": "Create workspace kind", + "operationId": "createWorkspaceKind", "parameters": [ { "description": "Kubernetes YAML manifest of a WorkspaceKind", @@ -215,6 +219,7 @@ "workspacekinds" ], "summary": "Get workspace kind", + "operationId": "getWorkspaceKind", "parameters": [ { "type": "string", @@ -267,7 +272,7 @@ }, "/workspaces": { "get": { - "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "description": "Returns a list of all workspaces across all namespaces.", "consumes": [ "application/json" ], @@ -277,20 +282,15 @@ "tags": [ "workspaces" ], - "summary": "List workspaces", + "summary": "List all workspaces", + "operationId": "listAllWorkspaces", "responses": { "200": { - "description": "Successful operation. Returns a list of workspaces.", + "description": "Successful operation. Returns a list of all workspaces.", "schema": { "$ref": "#/definitions/api.WorkspaceListEnvelope" } }, - "400": { - "description": "Bad Request. Invalid namespace format.", - "schema": { - "$ref": "#/definitions/api.ErrorEnvelope" - } - }, "401": { "description": "Unauthorized. Authentication is required.", "schema": { @@ -314,7 +314,7 @@ }, "/workspaces/{namespace}": { "get": { - "description": "Returns a list of workspaces. The endpoint supports two modes:\n1. List all workspaces across all namespaces (when no namespace is provided)\n2. List workspaces in a specific namespace (when namespace is provided)", + "description": "Returns a list of workspaces in a specific namespace.", "consumes": [ "application/json" ], @@ -324,12 +324,13 @@ "tags": [ "workspaces" ], - "summary": "List workspaces", + "summary": "List workspaces by namespace", + "operationId": "listWorkspacesByNamespace", "parameters": [ { "type": "string", "x-example": "kubeflow-user-example-com", - "description": "Namespace to filter workspaces. If not provided, returns all workspaces across all namespaces.", + "description": "Namespace to filter workspaces", "name": "namespace", "in": "path", "required": true @@ -337,7 +338,7 @@ ], "responses": { "200": { - "description": "Successful operation. Returns a list of workspaces.", + "description": "Successful operation. Returns a list of workspaces in the specified namespace.", "schema": { "$ref": "#/definitions/api.WorkspaceListEnvelope" } @@ -380,6 +381,7 @@ "workspaces" ], "summary": "Create workspace", + "operationId": "createWorkspace", "parameters": [ { "type": "string", @@ -464,6 +466,7 @@ "workspaces" ], "summary": "Pause or unpause a workspace", + "operationId": "updateWorkspacePauseState", "parameters": [ { "type": "string", @@ -562,6 +565,7 @@ "workspaces" ], "summary": "Get workspace", + "operationId": "getWorkspace", "parameters": [ { "type": "string", @@ -631,6 +635,7 @@ "workspaces" ], "summary": "Delete workspace", + "operationId": "deleteWorkspace", "parameters": [ { "type": "string",