docs: add error responses to openapi spec (#1684)

This commit is contained in:
Anthony Clerici
2026-08-11 19:26:48 +02:00
committed by GitHub
parent 155a1fcba0
commit 86cf73b86c
13 changed files with 93 additions and 8 deletions
@@ -52,6 +52,7 @@ type AppConfigController struct {
// @Accept json
// @Produce json
// @Success 200 {array} dto.PublicAppConfigVariableDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-configuration [get]
func (acc *AppConfigController) listAppConfigHandler(c *gin.Context) error {
dbConfig, err := acc.appConfigService.GetConfig(c.Request.Context())
@@ -89,6 +90,7 @@ func (acc *AppConfigController) listAppConfigHandler(c *gin.Context) error {
// @Accept json
// @Produce json
// @Success 200 {array} dto.AppConfigVariableDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-configuration/all [get]
func (acc *AppConfigController) listAllAppConfigHandler(c *gin.Context) error {
dbConfig, err := acc.appConfigService.GetConfig(c.Request.Context())
@@ -114,6 +116,7 @@ func (acc *AppConfigController) listAllAppConfigHandler(c *gin.Context) error {
// @Produce json
// @Param body body dto.AppConfigUpdateDto true "Application Configuration"
// @Success 200 {array} dto.AppConfigVariableDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-configuration [put]
func (acc *AppConfigController) updateAppConfigHandler(c *gin.Context) error {
var input dto.AppConfigUpdateDto
@@ -140,6 +143,7 @@ func (acc *AppConfigController) updateAppConfigHandler(c *gin.Context) error {
// @Description Send a test email to verify email configuration
// @Tags Application Configuration
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-configuration/test-email [post]
func (acc *AppConfigController) testEmailHandler(c *gin.Context) error {
dbConfig, err := acc.appConfigService.GetConfig(c.Request.Context())
@@ -10,6 +10,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/pocket-id/pocket-id/backend/internal/apperror"
_ "github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
"github.com/pocket-id/pocket-id/backend/internal/middleware"
"github.com/pocket-id/pocket-id/backend/internal/service"
@@ -55,6 +56,7 @@ type AppImagesController struct {
// @Produce image/jpeg
// @Produce image/svg+xml
// @Success 200 {file} binary "Logo image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/logo [get]
func (c *AppImagesController) getLogoHandler(ctx *gin.Context) error {
return c.getImage(ctx, logoImageName(ctx))
@@ -67,6 +69,7 @@ func (c *AppImagesController) getLogoHandler(ctx *gin.Context) error {
// @Produce image/png
// @Produce image/jpeg
// @Success 200 {file} binary "Email logo image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/email [get]
func (c *AppImagesController) getEmailLogoHandler(ctx *gin.Context) error {
return c.getImage(ctx, "logoEmail")
@@ -79,6 +82,7 @@ func (c *AppImagesController) getEmailLogoHandler(ctx *gin.Context) error {
// @Produce image/png
// @Produce image/jpeg
// @Success 200 {file} binary "Background image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/background [get]
func (c *AppImagesController) getBackgroundImageHandler(ctx *gin.Context) error {
return c.getImage(ctx, "background")
@@ -90,6 +94,7 @@ func (c *AppImagesController) getBackgroundImageHandler(ctx *gin.Context) error
// @Tags Application Images
// @Produce image/x-icon
// @Success 200 {file} binary "Favicon image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/favicon [get]
func (c *AppImagesController) getFaviconHandler(ctx *gin.Context) error {
return c.getImage(ctx, "favicon")
@@ -102,6 +107,7 @@ func (c *AppImagesController) getFaviconHandler(ctx *gin.Context) error {
// @Produce image/png
// @Produce image/jpeg
// @Success 200 {file} binary "Default profile picture image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/default-profile-picture [get]
func (c *AppImagesController) getDefaultProfilePicture(ctx *gin.Context) error {
return c.getImage(ctx, "default-profile-picture")
@@ -115,6 +121,7 @@ func (c *AppImagesController) getDefaultProfilePicture(ctx *gin.Context) error {
// @Param light query boolean false "Light mode logo (true) or dark mode logo (false)"
// @Param file formData file true "Logo image file"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/logo [put]
func (c *AppImagesController) updateLogoHandler(ctx *gin.Context) error {
file, err := httpserver.FormFile(ctx, "file")
@@ -136,6 +143,7 @@ func (c *AppImagesController) updateLogoHandler(ctx *gin.Context) error {
// @Tags Application Images
// @Param light query boolean false "Light mode logo (true) or dark mode logo (false)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/logo [delete]
func (c *AppImagesController) deleteLogoHandler(ctx *gin.Context) error {
if err := c.appImagesService.DeleteImage(ctx.Request.Context(), logoImageName(ctx)); err != nil {
@@ -161,6 +169,7 @@ func logoImageName(ctx *gin.Context) string {
// @Accept multipart/form-data
// @Param file formData file true "Email logo image file"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/email [put]
func (c *AppImagesController) updateEmailLogoHandler(ctx *gin.Context) error {
file, err := httpserver.FormFile(ctx, "file")
@@ -190,6 +199,7 @@ func (c *AppImagesController) updateEmailLogoHandler(ctx *gin.Context) error {
// @Accept multipart/form-data
// @Param file formData file true "Background image file"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/background [put]
func (c *AppImagesController) updateBackgroundImageHandler(ctx *gin.Context) error {
file, err := httpserver.FormFile(ctx, "file")
@@ -210,6 +220,7 @@ func (c *AppImagesController) updateBackgroundImageHandler(ctx *gin.Context) err
// @Description Delete the application background image
// @Tags Application Images
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/background [delete]
func (c *AppImagesController) deleteBackgroundImageHandler(ctx *gin.Context) error {
if err := c.appImagesService.DeleteImage(ctx.Request.Context(), "background"); err != nil {
@@ -227,6 +238,7 @@ func (c *AppImagesController) deleteBackgroundImageHandler(ctx *gin.Context) err
// @Accept multipart/form-data
// @Param file formData file true "Favicon file (.svg/.png/.ico)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/favicon [put]
func (c *AppImagesController) updateFaviconHandler(ctx *gin.Context) error {
file, err := httpserver.FormFile(ctx, "file")
@@ -268,6 +280,7 @@ func (c *AppImagesController) getImage(ctx *gin.Context, name string) error {
// @Accept multipart/form-data
// @Param file formData file true "Profile picture image file"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/default-profile-picture [put]
func (c *AppImagesController) updateDefaultProfilePicture(ctx *gin.Context) error {
file, err := httpserver.FormFile(ctx, "file")
@@ -288,6 +301,7 @@ func (c *AppImagesController) updateDefaultProfilePicture(ctx *gin.Context) erro
// @Description Delete the default profile picture image
// @Tags Application Images
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/application-images/default-profile-picture [delete]
func (c *AppImagesController) deleteDefaultProfilePicture(ctx *gin.Context) error {
if err := c.appImagesService.DeleteImage(ctx.Request.Context(), "default-profile-picture"); err != nil {
@@ -40,6 +40,7 @@ type AuditLogController struct {
// @Param sort[column] query string false "Column to sort by"
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Success 200 {object} dto.Paginated[dto.AuditLogDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/audit-logs [get]
func (alc *AuditLogController) listAuditLogsForUserHandler(c *gin.Context) error {
listRequestOptions := utils.ParseListRequestOptions(c)
@@ -82,6 +83,7 @@ func (alc *AuditLogController) listAuditLogsForUserHandler(c *gin.Context) error
// @Param sort[column] query string false "Column to sort by"
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Success 200 {object} dto.Paginated[dto.AuditLogDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/audit-logs/all [get]
func (alc *AuditLogController) listAllAuditLogsHandler(c *gin.Context) error {
listRequestOptions := utils.ParseListRequestOptions(c)
@@ -116,6 +118,7 @@ func (alc *AuditLogController) listAllAuditLogsHandler(c *gin.Context) error {
// @Description Get a list of all client names for audit log filtering
// @Tags Audit Logs
// @Success 200 {array} string "List of client names"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/audit-logs/filters/client-names [get]
func (alc *AuditLogController) listClientNamesHandler(c *gin.Context) error {
names, err := alc.auditLogService.ListClientNames(c.Request.Context())
@@ -132,6 +135,7 @@ func (alc *AuditLogController) listClientNamesHandler(c *gin.Context) error {
// @Description Get a list of all usernames with their IDs for audit log filtering
// @Tags Audit Logs
// @Success 200 {object} map[string]string "Map of user IDs to usernames"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/audit-logs/filters/users [get]
func (alc *AuditLogController) listUserNamesWithIdsHandler(c *gin.Context) error {
users, err := alc.auditLogService.ListUsernamesWithIds(c.Request.Context())
@@ -36,6 +36,7 @@ type CustomClaimController struct {
// @Tags Custom Claims
// @Produce json
// @Success 200 {array} string "List of suggested custom claim names"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/custom-claims/suggestions [get]
func (ccc *CustomClaimController) getSuggestionsHandler(c *gin.Context) error {
claims, err := ccc.customClaimService.GetSuggestions(c.Request.Context())
@@ -56,6 +57,7 @@ func (ccc *CustomClaimController) getSuggestionsHandler(c *gin.Context) error {
// @Param userId path string true "User ID"
// @Param claims body []dto.CustomClaimCreateDto true "List of custom claims to set for the user"
// @Success 200 {array} dto.CustomClaimDto "Updated custom claims"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/custom-claims/user/{userId} [put]
func (ccc *CustomClaimController) UpdateCustomClaimsForUserHandler(c *gin.Context) error {
var input []dto.CustomClaimCreateDto
@@ -88,6 +90,7 @@ func (ccc *CustomClaimController) UpdateCustomClaimsForUserHandler(c *gin.Contex
// @Param userGroupId path string true "User Group ID"
// @Param claims body []dto.CustomClaimCreateDto true "List of custom claims to set for the user group"
// @Success 200 {array} dto.CustomClaimDto "Updated custom claims"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/custom-claims/user-group/{userGroupId} [put]
func (ccc *CustomClaimController) UpdateCustomClaimsForUserGroupHandler(c *gin.Context) error {
var input []dto.CustomClaimCreateDto
@@ -4,6 +4,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
_ "github.com/pocket-id/pocket-id/backend/internal/dto"
)
// NewHealthzController creates a new controller for the healthcheck endpoints
@@ -23,6 +25,7 @@ type HealthzController struct{}
// @Description Responds with a successful status code to healthcheck requests
// @Tags Health
// @Success 204 ""
// @Failure default {object} dto.ErrorDto "Error"
// @Router /healthz [get]
func (hc *HealthzController) healthzHandler(c *gin.Context) {
c.Status(http.StatusNoContent)
@@ -66,6 +66,7 @@ type OidcController struct {
// @Produce json
// @Param id path string true "Client ID"
// @Success 200 {object} dto.OidcClientMetaDataDto "Client metadata"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/meta [get]
func (oc *OidcController) getClientMetaDataHandler(c *gin.Context) error {
clientId := c.Param("id")
@@ -91,6 +92,7 @@ func (oc *OidcController) getClientMetaDataHandler(c *gin.Context) error {
// @Produce json
// @Param id path string true "Client ID"
// @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Client information"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id} [get]
func (oc *OidcController) getClientHandler(c *gin.Context) error {
clientId := c.Param("id")
@@ -119,6 +121,7 @@ func (oc *OidcController) getClientHandler(c *gin.Context) error {
// @Param sort[column] query string false "Column to sort by"
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Success 200 {object} dto.Paginated[dto.OidcClientWithAllowedGroupsCountDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients [get]
func (oc *OidcController) listClientsHandler(c *gin.Context) error {
searchTerm := c.Query("search")
@@ -160,6 +163,7 @@ func (oc *OidcController) listClientsHandler(c *gin.Context) error {
// @Produce json
// @Param client body dto.OidcClientCreateDto true "Client information"
// @Success 201 {object} dto.OidcClientWithAllowedUserGroupsDto "Created client"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients [post]
func (oc *OidcController) createClientHandler(c *gin.Context) error {
var input dto.OidcClientCreateDto
@@ -189,6 +193,7 @@ func (oc *OidcController) createClientHandler(c *gin.Context) error {
// @Tags OIDC
// @Param id path string true "Client ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id} [delete]
func (oc *OidcController) deleteClientHandler(c *gin.Context) error {
err := oc.oidcService.DeleteClient(c.Request.Context(), c.Param("id"))
@@ -209,6 +214,7 @@ func (oc *OidcController) deleteClientHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param client body dto.OidcClientUpdateDto true "Client information"
// @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Updated client"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id} [put]
func (oc *OidcController) updateClientHandler(c *gin.Context) error {
var input dto.OidcClientUpdateDto
@@ -239,6 +245,7 @@ func (oc *OidcController) updateClientHandler(c *gin.Context) error {
// @Produce json
// @Param id path string true "Client ID"
// @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Refreshed client"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/refresh [post]
func (oc *OidcController) refreshClientMetadataHandler(c *gin.Context) error {
client, err := oc.oidcService.RefreshClientMetadata(c.Request.Context(), c.Param("id"))
@@ -264,6 +271,7 @@ func (oc *OidcController) refreshClientMetadataHandler(c *gin.Context) error {
// @Produce json
// @Param id path string true "Client ID"
// @Success 200 {array} dto.OidcClientSecretDto "Client secrets"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/secrets [get]
func (oc *OidcController) listClientSecretsHandler(c *gin.Context) error {
secrets, err := oc.oidcService.ListClientSecrets(c.Request.Context(), c.Param("id"))
@@ -290,6 +298,7 @@ func (oc *OidcController) listClientSecretsHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param payload body dto.OidcClientSecretCreateDto false "Client secret"
// @Success 201 {object} dto.OidcClientSecretCreatedDto "Created client secret"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/secrets [post]
func (oc *OidcController) createClientSecretHandler(c *gin.Context) error {
var input dto.OidcClientSecretCreateDto
@@ -321,6 +330,7 @@ func (oc *OidcController) createClientSecretHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param secretId path string true "Client secret ID"
// @Success 204 "No content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/secrets/{secretId} [delete]
func (oc *OidcController) deleteClientSecretHandler(c *gin.Context) error {
err := oc.oidcService.DeleteClientSecret(c.Request.Context(), c.Param("id"), c.Param("secretId"))
@@ -342,6 +352,7 @@ func (oc *OidcController) deleteClientSecretHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param light query boolean false "Light mode logo (true) or dark mode logo (false)"
// @Success 200 {file} binary "Logo image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/logo [get]
func (oc *OidcController) getClientLogoHandler(c *gin.Context) error {
lightLogo, _ := strconv.ParseBool(c.DefaultQuery("light", "true"))
@@ -368,6 +379,7 @@ func (oc *OidcController) getClientLogoHandler(c *gin.Context) error {
// @Param file formData file true "Logo image file (PNG, JPG, or SVG)"
// @Param light query boolean false "Light mode logo (true) or dark mode logo (false)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/logo [post]
func (oc *OidcController) updateClientLogoHandler(c *gin.Context) error {
file, err := httpserver.FormFile(c, "file")
@@ -393,6 +405,7 @@ func (oc *OidcController) updateClientLogoHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param light query boolean false "Light mode logo (true) or dark mode logo (false)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/logo [delete]
func (oc *OidcController) deleteClientLogoHandler(c *gin.Context) error {
var err error
@@ -421,6 +434,7 @@ func (oc *OidcController) deleteClientLogoHandler(c *gin.Context) error {
// @Param id path string true "Client ID"
// @Param groups body dto.OidcUpdateAllowedUserGroupsDto true "User group IDs"
// @Success 200 {object} dto.OidcClientDto "Updated client"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/allowed-user-groups [put]
func (oc *OidcController) updateAllowedUserGroupsHandler(c *gin.Context) error {
var input dto.OidcUpdateAllowedUserGroupsDto
@@ -453,6 +467,7 @@ func (oc *OidcController) updateAllowedUserGroupsHandler(c *gin.Context) error {
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Param filters[hasLaunchURL] query bool false "Filter clients by whether a launch URL is configured"
// @Success 200 {object} dto.Paginated[dto.AuthorizedOidcClientDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/users/me/authorized-clients [get]
func (oc *OidcController) listOwnAuthorizedClientsHandler(c *gin.Context) error {
userID := c.GetString("userID")
@@ -470,6 +485,7 @@ func (oc *OidcController) listOwnAuthorizedClientsHandler(c *gin.Context) error
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Param filters[hasLaunchURL] query bool false "Filter clients by whether a launch URL is configured"
// @Success 200 {object} dto.Paginated[dto.AuthorizedOidcClientDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/users/{id}/authorized-clients [get]
func (oc *OidcController) listAuthorizedClientsHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -503,6 +519,7 @@ func (oc *OidcController) listAuthorizedClients(c *gin.Context, userID string) e
// @Tags OIDC
// @Param clientId path string true "Client ID to revoke authorization for"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/users/me/authorized-clients/{clientId} [delete]
func (oc *OidcController) revokeOwnClientAuthorizationHandler(c *gin.Context) error {
clientID := c.Param("clientId")
@@ -528,6 +545,7 @@ func (oc *OidcController) revokeOwnClientAuthorizationHandler(c *gin.Context) er
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Param filters[hasLaunchURL] query bool false "Filter clients by whether a launch URL is configured"
// @Success 200 {object} dto.Paginated[dto.AccessibleOidcClientDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/users/me/clients [get]
func (oc *OidcController) listOwnAccessibleClientsHandler(c *gin.Context) error {
listRequestOptions := utils.ParseListRequestOptions(c)
@@ -556,6 +574,7 @@ func (oc *OidcController) listOwnAccessibleClientsHandler(c *gin.Context) error
// @Param scopes query string false "Scopes to include in the preview (comma-separated)"
// @Success 200 {object} dto.OidcClientPreviewDto "Preview data including ID token, access token, and userinfo payloads"
// @Security BearerAuth
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/preview/{userId} [get]
func (oc *OidcController) getClientPreviewHandler(c *gin.Context) error {
clientID := c.Param("id")
@@ -596,6 +615,7 @@ func (oc *OidcController) getClientPreviewHandler(c *gin.Context) error {
// @Produce json
// @Param id path string true "Client ID"
// @Success 200 {object} dto.ScimServiceProviderDTO "SCIM service provider configuration"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/oidc/clients/{id}/scim-service-provider [get]
func (oc *OidcController) getClientScimServiceProviderHandler(c *gin.Context) error {
clientID := c.Param("id")
@@ -31,6 +31,7 @@ type ScimController struct {
// @Tags SCIM
// @Param id path string true "Service Provider ID"
// @Success 200 "OK"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/scim/service-provider/{id}/sync [post]
func (c *ScimController) syncServiceProviderHandler(ctx *gin.Context) error {
err := c.scimService.SyncServiceProvider(ctx.Request.Context(), ctx.Param("id"))
@@ -50,6 +51,7 @@ func (c *ScimController) syncServiceProviderHandler(ctx *gin.Context) error {
// @Produce json
// @Param serviceProvider body dto.ScimServiceProviderCreateDTO true "SCIM service provider information"
// @Success 201 {object} dto.ScimServiceProviderDTO "Created SCIM service provider"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/scim/service-provider [post]
func (c *ScimController) createServiceProviderHandler(ctx *gin.Context) error {
var input dto.ScimServiceProviderCreateDTO
@@ -80,6 +82,7 @@ func (c *ScimController) createServiceProviderHandler(ctx *gin.Context) error {
// @Param id path string true "Service Provider ID"
// @Param serviceProvider body dto.ScimServiceProviderCreateDTO true "SCIM service provider information"
// @Success 200 {object} dto.ScimServiceProviderDTO "Updated SCIM service provider"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/scim/service-provider/{id} [put]
func (c *ScimController) updateServiceProviderHandler(ctx *gin.Context) error {
var input dto.ScimServiceProviderCreateDTO
@@ -107,6 +110,7 @@ func (c *ScimController) updateServiceProviderHandler(ctx *gin.Context) error {
// @Tags SCIM
// @Param id path string true "Service Provider ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/scim/service-provider/{id} [delete]
func (c *ScimController) deleteServiceProviderHandler(ctx *gin.Context) error {
err := c.scimService.DeleteServiceProvider(ctx.Request.Context(), ctx.Param("id"))
@@ -61,6 +61,7 @@ type UserController struct {
// @Tags Users,User Groups
// @Param id path string true "User ID"
// @Success 200 {array} dto.UserGroupDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/groups [get]
func (uc *UserController) getUserGroupsHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -84,6 +85,7 @@ func (uc *UserController) getUserGroupsHandler(c *gin.Context) error {
// @Tags Users
// @Param id path string true "User ID"
// @Success 200 {array} dto.WebauthnCredentialDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/webauthn-credentials [get]
func (uc *UserController) listUserWebauthnCredentialsHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -116,6 +118,7 @@ func (uc *UserController) listUserWebauthnCredentialsHandler(c *gin.Context) err
// @Param sort[column] query string false "Column to sort by"
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Success 200 {object} dto.Paginated[dto.UserDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users [get]
func (uc *UserController) listUsersHandler(c *gin.Context) error {
searchTerm := c.Query("search")
@@ -144,6 +147,7 @@ func (uc *UserController) listUsersHandler(c *gin.Context) error {
// @Tags Users
// @Param id path string true "User ID"
// @Success 200 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id} [get]
func (uc *UserController) getUserHandler(c *gin.Context) error {
user, err := uc.userService.GetUser(c.Request.Context(), c.Param("id"))
@@ -165,6 +169,7 @@ func (uc *UserController) getUserHandler(c *gin.Context) error {
// @Description Retrieve information about the currently authenticated user
// @Tags Users
// @Success 200 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/me [get]
func (uc *UserController) getCurrentUserHandler(c *gin.Context) error {
user, err := uc.userService.GetUser(c.Request.Context(), c.GetString("userID"))
@@ -187,6 +192,7 @@ func (uc *UserController) getCurrentUserHandler(c *gin.Context) error {
// @Tags Users
// @Param id path string true "User ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id} [delete]
func (uc *UserController) deleteUserHandler(c *gin.Context) error {
dbConfig, err := uc.appConfigService.GetConfig(c.Request.Context())
@@ -209,6 +215,7 @@ func (uc *UserController) deleteUserHandler(c *gin.Context) error {
// @Param id path string true "User ID"
// @Param credentialId path string true "Credential ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/webauthn-credentials/{credentialId} [delete]
func (uc *UserController) deleteUserWebauthnCredentialHandler(c *gin.Context) error {
err := uc.webAuthnService.DeleteCredential(
@@ -233,6 +240,7 @@ func (uc *UserController) deleteUserWebauthnCredentialHandler(c *gin.Context) er
// @Tags Users
// @Param user body dto.UserCreateDto true "User information"
// @Success 201 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users [post]
func (uc *UserController) createUserHandler(c *gin.Context) error {
dbConfig, err := uc.appConfigService.GetConfig(c.Request.Context())
@@ -266,6 +274,7 @@ func (uc *UserController) createUserHandler(c *gin.Context) error {
// @Param id path string true "User ID"
// @Param user body dto.UserCreateDto true "User information"
// @Success 200 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id} [put]
func (uc *UserController) updateUserHandler(c *gin.Context) error {
return uc.updateUser(c, false)
@@ -277,6 +286,7 @@ func (uc *UserController) updateUserHandler(c *gin.Context) error {
// @Tags Users
// @Param user body dto.UserCreateDto true "User information"
// @Success 200 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/me [put]
func (uc *UserController) updateCurrentUserHandler(c *gin.Context) error {
return uc.updateUser(c, true)
@@ -289,6 +299,7 @@ func (uc *UserController) updateCurrentUserHandler(c *gin.Context) error {
// @Produce image/png
// @Param id path string true "User ID"
// @Success 200 {file} binary "PNG image"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/profile-picture.png [get]
func (uc *UserController) getUserProfilePictureHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -316,6 +327,7 @@ func (uc *UserController) getUserProfilePictureHandler(c *gin.Context) error {
// @Param id path string true "User ID"
// @Param file formData file true "Profile picture image file (PNG, JPG, or JPEG)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/profile-picture [put]
func (uc *UserController) updateUserProfilePictureHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -345,6 +357,7 @@ func (uc *UserController) updateUserProfilePictureHandler(c *gin.Context) error
// @Produce json
// @Param file formData file true "Profile picture image file (PNG, JPG, or JPEG)"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/me/profile-picture [put]
func (uc *UserController) updateCurrentUserProfilePictureHandler(c *gin.Context) error {
userID := c.GetString("userID")
@@ -373,6 +386,7 @@ func (uc *UserController) updateCurrentUserProfilePictureHandler(c *gin.Context)
// @Param id path string true "User ID"
// @Param groups body dto.UserUpdateUserGroupDto true "User group IDs"
// @Success 200 {object} dto.UserDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/user-groups [put]
func (uc *UserController) updateUserGroups(c *gin.Context) error {
var input dto.UserUpdateUserGroupDto
@@ -434,6 +448,7 @@ func (uc *UserController) updateUser(c *gin.Context, updateOwnUser bool) error {
// @Produce json
// @Param id path string true "User ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/{id}/profile-picture [delete]
func (uc *UserController) resetUserProfilePictureHandler(c *gin.Context) error {
userID := c.Param("id")
@@ -452,6 +467,7 @@ func (uc *UserController) resetUserProfilePictureHandler(c *gin.Context) error {
// @Tags Users
// @Produce json
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/users/me/profile-picture [delete]
func (uc *UserController) resetCurrentUserProfilePictureHandler(c *gin.Context) error {
userID := c.GetString("userID")
@@ -51,6 +51,7 @@ type UserGroupController struct {
// @Param sort[column] query string false "Column to sort by"
// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc")
// @Success 200 {object} dto.Paginated[dto.UserGroupMinimalDto]
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups [get]
func (ugc *UserGroupController) list(c *gin.Context) error {
searchTerm := c.Query("search")
@@ -90,6 +91,7 @@ func (ugc *UserGroupController) list(c *gin.Context) error {
// @Produce json
// @Param id path string true "User Group ID"
// @Success 200 {object} dto.UserGroupDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups/{id} [get]
func (ugc *UserGroupController) get(c *gin.Context) error {
group, err := ugc.UserGroupService.Get(c.Request.Context(), c.Param("id"))
@@ -114,6 +116,7 @@ func (ugc *UserGroupController) get(c *gin.Context) error {
// @Produce json
// @Param userGroup body dto.UserGroupCreateDto true "User group information"
// @Success 201 {object} dto.UserGroupDto "Created user group"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups [post]
func (ugc *UserGroupController) create(c *gin.Context) error {
var input dto.UserGroupCreateDto
@@ -144,6 +147,7 @@ func (ugc *UserGroupController) create(c *gin.Context) error {
// @Param id path string true "User Group ID"
// @Param userGroup body dto.UserGroupCreateDto true "User group information"
// @Success 200 {object} dto.UserGroupDto "Updated user group"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups/{id} [put]
func (ugc *UserGroupController) update(c *gin.Context) error {
dbConfig, err := ugc.appConfigService.GetConfig(c.Request.Context())
@@ -178,6 +182,7 @@ func (ugc *UserGroupController) update(c *gin.Context) error {
// @Produce json
// @Param id path string true "User Group ID"
// @Success 204 "No Content"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups/{id} [delete]
func (ugc *UserGroupController) delete(c *gin.Context) error {
dbConfig, err := ugc.appConfigService.GetConfig(c.Request.Context())
@@ -202,6 +207,7 @@ func (ugc *UserGroupController) delete(c *gin.Context) error {
// @Param id path string true "User Group ID"
// @Param users body dto.UserGroupUpdateUsersDto true "List of user IDs to assign to this group"
// @Success 200 {object} dto.UserGroupDto
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups/{id}/users [put]
func (ugc *UserGroupController) updateUsers(c *gin.Context) error {
var input dto.UserGroupUpdateUsersDto
@@ -232,6 +238,7 @@ func (ugc *UserGroupController) updateUsers(c *gin.Context) error {
// @Param id path string true "User Group ID"
// @Param groups body dto.UserGroupUpdateAllowedOidcClientsDto true "OIDC client IDs to allow"
// @Success 200 {object} dto.UserGroupDto "Updated user group"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/user-groups/{id}/allowed-oidc-clients [put]
func (ugc *UserGroupController) updateAllowedOidcClients(c *gin.Context) error {
var input dto.UserGroupUpdateAllowedOidcClientsDto
@@ -6,6 +6,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/pocket-id/pocket-id/backend/internal/common"
_ "github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
"github.com/pocket-id/pocket-id/backend/internal/middleware"
"github.com/pocket-id/pocket-id/backend/internal/service"
@@ -28,6 +29,7 @@ type VersionController struct {
// @Tags Version
// @Produce json
// @Success 200 {object} map[string]string "Latest version information"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/version/latest [get]
func (vc *VersionController) getLatestVersionHandler(c *gin.Context) error {
tag, err := vc.versionService.GetLatestVersion(c.Request.Context())
@@ -48,6 +50,7 @@ func (vc *VersionController) getLatestVersionHandler(c *gin.Context) error {
// @Tags Version
// @Produce json
// @Success 200 {object} map[string]string "Current version information"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /api/version/current [get]
func (vc *VersionController) getCurrentVersionHandler(c *gin.Context) error {
c.JSON(http.StatusOK, gin.H{
@@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/pocket-id/pocket-id/backend/internal/common"
_ "github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
"github.com/pocket-id/pocket-id/backend/internal/service"
)
@@ -37,6 +38,7 @@ type WellKnownController struct {
// @Tags Well Known
// @Produce json
// @Success 200 {object} object "{ \"keys\": []interface{} }"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /.well-known/jwks.json [get]
func (wkc *WellKnownController) jwksHandler(c *gin.Context) error {
jwks, err := wkc.jwtService.GetPublicJWKSAsJSON()
@@ -53,6 +55,7 @@ func (wkc *WellKnownController) jwksHandler(c *gin.Context) error {
// @Description Returns the OpenID Connect discovery document with endpoints and capabilities
// @Tags Well Known
// @Success 200 {object} object "OpenID Connect configuration"
// @Failure default {object} dto.ErrorDto "Error"
// @Router /.well-known/openid-configuration [get]
func (wkc *WellKnownController) openIDConfigurationHandler(c *gin.Context) error {
oidcConfig, err := wkc.computeOIDCConfiguration()
+11
View File
@@ -0,0 +1,11 @@
package dto
import "github.com/pocket-id/pocket-id/backend/internal/apperror"
// ErrorDto is the response body returned for every failed request.
type ErrorDto struct {
Error string `json:"error"`
Code apperror.Code `json:"code"`
Details map[string]any `json:"details,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
+1 -8
View File
@@ -106,13 +106,6 @@ func (m *ErrorHandlerMiddleware) Add() gin.HandlerFunc {
}
}
type errorResponseBody struct {
Error string `json:"error"`
Code apperror.Code `json:"code"`
Details map[string]any `json:"details,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
func classifyError(err error) classifiedError {
var structuredErr *apperror.Error
if errors.As(err, &structuredErr) && structuredErr != nil {
@@ -188,7 +181,7 @@ func writeErrorResponse(c *gin.Context, classified classifiedError, requestID st
details = nil
}
response := errorResponseBody{
response := dto.ErrorDto{
Error: classified.message,
Code: classified.code,
Details: details,