Skip to content

Commit 8f723d1

Browse files
authored
Merge pull request #270 from shamanec/feature/refactor-api-responses
Refactor API responses to use a specific structure
2 parents e39a1a1 + cb1deff commit 8f723d1

19 files changed

Lines changed: 595 additions & 639 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ server.key
1212
jsconfig.json
1313
.vscode/launch.json
1414
Provider1/
15-
go-ios*
15+
go-ios*
16+
memory/*

common/api/api.go

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,57 @@ import (
1616
"github.com/gin-gonic/gin"
1717
)
1818

19-
func GenericResponse(c *gin.Context, statusCode int, message string, result interface{}) {
20-
c.JSON(statusCode, models.APIResponse{
21-
Message: message,
22-
Result: result,
23-
})
19+
// OK sends a 200 response with result payload.
20+
func OK[T any](c *gin.Context, message string, result T) {
21+
c.JSON(http.StatusOK, models.APIResponse[T]{Success: true, Message: message, Result: result})
2422
}
2523

26-
func InternalServerErrorResponse(c *gin.Context, message string, result interface{}) {
27-
GenericResponse(c, http.StatusInternalServerError, message, result)
24+
// OKMessage sends a 200 response with a message only (no result payload).
25+
func OKMessage(c *gin.Context, message string) {
26+
c.JSON(http.StatusOK, models.APIResponse[any]{Success: true, Message: message})
2827
}
2928

30-
func OKResponse(c *gin.Context, message string, result interface{}) {
31-
GenericResponse(c, http.StatusOK, message, result)
29+
// Created sends a 201 response with result payload.
30+
func Created[T any](c *gin.Context, message string, result T) {
31+
c.JSON(http.StatusCreated, models.APIResponse[T]{Success: true, Message: message, Result: result})
3232
}
3333

34-
func NotFoundResponse(c *gin.Context, message string, result interface{}) {
35-
GenericResponse(c, http.StatusNotFound, message, result)
34+
// ErrorResponse sends an error response with the given status code.
35+
func ErrorResponse(c *gin.Context, status int, message string) {
36+
c.JSON(status, models.APIResponse[any]{Success: false, Message: message})
3637
}
3738

38-
func BadRequestResponse(c *gin.Context, message string, result interface{}) {
39-
GenericResponse(c, http.StatusBadRequest, message, result)
39+
// BadRequest sends a 400 error response.
40+
func BadRequest(c *gin.Context, message string) {
41+
ErrorResponse(c, http.StatusBadRequest, message)
4042
}
4143

42-
func ForbiddenResponse(c *gin.Context, message string, result interface{}) {
43-
GenericResponse(c, http.StatusForbidden, message, result)
44+
// Unauthorized sends a 401 error response.
45+
func Unauthorized(c *gin.Context, message string) {
46+
ErrorResponse(c, http.StatusUnauthorized, message)
47+
}
48+
49+
// Forbidden sends a 403 error response.
50+
func Forbidden(c *gin.Context, message string) {
51+
ErrorResponse(c, http.StatusForbidden, message)
52+
}
53+
54+
// NotFound sends a 404 error response.
55+
func NotFound(c *gin.Context, message string) {
56+
ErrorResponse(c, http.StatusNotFound, message)
57+
}
58+
59+
// Conflict sends a 409 error response.
60+
func Conflict(c *gin.Context, message string) {
61+
ErrorResponse(c, http.StatusConflict, message)
62+
}
63+
64+
// InternalError sends a 500 error response.
65+
func InternalError(c *gin.Context, message string) {
66+
ErrorResponse(c, http.StatusInternalServerError, message)
67+
}
68+
69+
// AbortUnauthorized aborts the request chain and sends a 401 response.
70+
func AbortUnauthorized(c *gin.Context, message string) {
71+
c.AbortWithStatusJSON(http.StatusUnauthorized, models.APIResponse[any]{Success: false, Message: message})
4472
}

common/models/hub_api.go

Lines changed: 0 additions & 29 deletions
This file was deleted.

common/models/responses.go

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,65 @@
99

1010
package models
1111

12-
// SuccessResponse represents a successful API response
13-
type SuccessResponse struct {
14-
Message string `json:"message" example:"Operation completed successfully"`
12+
// APIResponse is the standard response envelope for all GADS API endpoints.
13+
// Use the concrete type aliases below for Swagger annotations.
14+
type APIResponse[T any] struct {
15+
Success bool `json:"success" example:"true"`
16+
Message string `json:"message,omitempty" example:"Operation completed successfully"`
17+
Result T `json:"result,omitempty"`
18+
}
19+
20+
// Page is a generic paginated result wrapper.
21+
type Page[T any] struct {
22+
Items []T `json:"items"`
23+
Total int64 `json:"total"`
24+
Page int `json:"page,omitempty"`
25+
TotalPages int `json:"total_pages,omitempty"`
26+
}
27+
28+
// Concrete page types for Swagger annotations.
29+
type WorkspacesPage = Page[WorkspaceWithDeviceCount]
30+
type AuditLogsPage = Page[SecretKeyAuditLogResponse]
31+
32+
// Concrete types for Swagger annotations (swag does not support Go generics directly).
33+
type DeviceResponse = APIResponse[Device]
34+
type DeviceListResponse = APIResponse[[]Device]
35+
type UserResponse = APIResponse[User]
36+
type UserListResponse = APIResponse[[]User]
37+
type WorkspaceResponse = APIResponse[Workspace]
38+
type WorkspacePageResponse = APIResponse[WorkspacesPage]
39+
type ProviderResponse = APIResponse[Provider]
40+
type ProviderListResponse = APIResponse[[]Provider]
41+
type AuthTokenResponse = APIResponse[AuthResponse]
42+
type SecretKeyListResponse = APIResponse[[]SecretKeyResponse]
43+
type CredentialCreateResponse = APIResponse[CreateCredentialResponse]
44+
type CredentialListResponse = APIResponse[ClientCredentialsListResponse]
45+
type CredentialGetResponse = APIResponse[CredentialResponse]
46+
type FileListResponse = APIResponse[[]DBFile]
47+
type StringDataResponse = APIResponse[string]
48+
type CustomActionResponse = APIResponse[CustomAction]
49+
type CustomActionListResponse = APIResponse[[]CustomAction]
50+
type InstalledAppsResponse = APIResponse[[]string]
51+
type StreamSettingsResponse = APIResponse[StreamSettings]
52+
type MinioConfigResponse = APIResponse[MinioConfig]
53+
type TURNConfigResponse = APIResponse[TURNConfig]
54+
type SysStatusResponse = APIResponse[SystemStatusResponse]
55+
type LogsResponse = APIResponse[[]LogEntry]
56+
57+
// ErrorResponse is the Swagger schema for error API responses (no result payload).
58+
type ErrorResponse struct {
59+
Success bool `json:"success" example:"false"`
60+
Message string `json:"message" example:"An error occurred"`
1561
}
1662

17-
// ErrorResponse represents an error API response
18-
type ErrorResponse struct {
19-
Error string `json:"error" example:"Something went wrong"`
63+
// SuccessResponse is the Swagger schema for success API responses without a result payload.
64+
type SuccessResponse struct {
65+
Success bool `json:"success" example:"true"`
66+
Message string `json:"message" example:"Operation completed successfully"`
2067
}
2168

22-
// HealthResponse represents the health check response
23-
type HealthResponse struct {
24-
Message string `json:"message" example:"ok"`
69+
type OAuthErrorResponse struct {
70+
Error string `json:"error"`
2571
}
2672

2773
// SecretKeyResponse represents a secret key response (without exposing the actual key)
@@ -157,3 +203,14 @@ type ClientCredentialsListResponse struct {
157203
Credentials []CredentialResponse `json:"credentials"`
158204
Total int64 `json:"total" example:"5"`
159205
}
206+
207+
// System status response structures
208+
type SystemStatusMessage struct {
209+
Type string `json:"type"`
210+
Message string `json:"message"`
211+
Action string `json:"action"`
212+
}
213+
214+
type SystemStatusResponse struct {
215+
Messages []SystemStatusMessage `json:"messages"`
216+
}

hub-ui

0 commit comments

Comments
 (0)