Some checks failed
Build and Release / Create Release (push) Has been skipped
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 2m28s
Build and Release / Unit Tests (push) Successful in 2m31s
Build and Release / Lint (push) Failing after 2m57s
Build and Release / Build Binaries (amd64, darwin) (push) Has been skipped
Build and Release / Build Binaries (amd64, linux) (push) Has been skipped
Build and Release / Build Binaries (amd64, windows) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin) (push) Has been skipped
Build and Release / Build Binaries (arm64, linux) (push) Has been skipped
- New files: Copyright 2026 MarketAlly - Modified files: Copyright YYYY The Gitea Authors and MarketAlly 🤖 Generated with Claude Code Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
130 lines
3.5 KiB
Go
130 lines
3.5 KiB
Go
// Copyright 2026 MarketAlly. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"code.gitea.io/gitea/modules/setting"
|
|
)
|
|
|
|
// APIErrorResponse is the top-level error response wrapper
|
|
type APIErrorResponse struct {
|
|
Error *APIError `json:"error"`
|
|
}
|
|
|
|
// APIError represents a structured API error following RFC 7807 Problem Details
|
|
// with additional fields for AI-friendly error handling
|
|
type APIError struct {
|
|
// Machine-readable error code (e.g., "REPO_NOT_FOUND")
|
|
Code string `json:"code"`
|
|
|
|
// Human-readable error message
|
|
Message string `json:"message"`
|
|
|
|
// HTTP status code
|
|
Status int `json:"status"`
|
|
|
|
// Additional context about the error
|
|
Details map[string]any `json:"details,omitempty"`
|
|
|
|
// URL to documentation about this error
|
|
DocumentationURL string `json:"documentation_url,omitempty"`
|
|
|
|
// Unique request ID for tracing
|
|
RequestID string `json:"request_id,omitempty"`
|
|
|
|
// Suggested actions or alternatives
|
|
Suggestions []string `json:"suggestions,omitempty"`
|
|
|
|
// RFC 7807 Problem Details fields
|
|
Type string `json:"type,omitempty"` // URI reference identifying the problem type
|
|
Title string `json:"title,omitempty"` // Short summary of the problem type
|
|
Instance string `json:"instance,omitempty"` // URI reference for this specific occurrence
|
|
}
|
|
|
|
// NewAPIError creates a new structured API error
|
|
func NewAPIError(code ErrorCode, requestID string) *APIError {
|
|
docURL := fmt.Sprintf("%s/api/errors#%s", setting.AppURL, code)
|
|
|
|
return &APIError{
|
|
Code: code.String(),
|
|
Message: code.Message(),
|
|
Status: code.HTTPStatus(),
|
|
DocumentationURL: docURL,
|
|
RequestID: requestID,
|
|
Type: "about:blank",
|
|
Title: code.Message(),
|
|
Instance: requestID,
|
|
}
|
|
}
|
|
|
|
// WithDetails adds details to the error
|
|
func (e *APIError) WithDetails(details map[string]any) *APIError {
|
|
e.Details = details
|
|
return e
|
|
}
|
|
|
|
// WithDetail adds a single detail to the error
|
|
func (e *APIError) WithDetail(key string, value any) *APIError {
|
|
if e.Details == nil {
|
|
e.Details = make(map[string]any)
|
|
}
|
|
e.Details[key] = value
|
|
return e
|
|
}
|
|
|
|
// WithMessage overrides the default message
|
|
func (e *APIError) WithMessage(message string) *APIError {
|
|
e.Message = message
|
|
e.Title = message
|
|
return e
|
|
}
|
|
|
|
// WithSuggestions adds suggested actions
|
|
func (e *APIError) WithSuggestions(suggestions ...string) *APIError {
|
|
e.Suggestions = append(e.Suggestions, suggestions...)
|
|
return e
|
|
}
|
|
|
|
// Response wraps the error in an APIErrorResponse
|
|
func (e *APIError) Response() *APIErrorResponse {
|
|
return &APIErrorResponse{Error: e}
|
|
}
|
|
|
|
// ValidationError represents a field-level validation error
|
|
type ValidationError struct {
|
|
Field string `json:"field"`
|
|
Message string `json:"message"`
|
|
Code string `json:"code,omitempty"`
|
|
}
|
|
|
|
// APIValidationError represents a validation error with field-level details
|
|
type APIValidationError struct {
|
|
*APIError
|
|
Errors []ValidationError `json:"errors,omitempty"`
|
|
}
|
|
|
|
// NewValidationError creates a new validation error
|
|
func NewValidationError(requestID string, errors ...ValidationError) *APIValidationError {
|
|
baseErr := NewAPIError(ValInvalidInput, requestID)
|
|
return &APIValidationError{
|
|
APIError: baseErr,
|
|
Errors: errors,
|
|
}
|
|
}
|
|
|
|
// AddFieldError adds a field validation error
|
|
func (e *APIValidationError) AddFieldError(field, message string, code ...string) *APIValidationError {
|
|
ve := ValidationError{
|
|
Field: field,
|
|
Message: message,
|
|
}
|
|
if len(code) > 0 {
|
|
ve.Code = code[0]
|
|
}
|
|
e.Errors = append(e.Errors, ve)
|
|
return e
|
|
}
|