mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat(api): error codes, idempotency keys, cursor pagination
- Stable machine-readable error codes alongside the error message (UNAUTHENTICATED, INVALID_TOKEN, ADMIN_REQUIRED, SCOPE_INSUFFICIENT, IDEMPOTENCY_IN_PROGRESS); CLI renders "CODE: message". - Idempotency middleware on authed/admin groups: POST requests with an Idempotency-Key header replay the first response for 24h (Redis-backed, caller-scoped); concurrent duplicates get 409. X-Idempotent-Replay header marks replays. - Shared pagination helpers: ?cursor= (opaque, preferred) alongside legacy ?page= on projects and deployments lists; pagination meta includes next_cursor; invalid cursors fail soft to page 1. - CLI --idempotency-key flag for safe scripted retries. - OpenAPI updated: error envelope, cursor params, idempotency contract. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
485e41a817
commit
18f78f00a3
15 files changed
+454
-56
No files matched your search
@@ -8,7 +8,6 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -55,18 +54,9 @@ func handleGetProjects(c *gin.Context) {
|
||||
db := c.MustGet("db").(*database.DB)
|
||||
queries := sqlcdb.New(db.DB)
|
||||
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||||
offset, limit := pageWindow(c, 10, 100)
|
||||
search := strings.TrimSpace(c.DefaultQuery("search", ""))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if limit > 100 || limit < 1 {
|
||||
limit = 10
|
||||
}
|
||||
offset := (page - 1) * limit
|
||||
|
||||
searchParam := sql.NullString{}
|
||||
if search != "" {
|
||||
searchParam = sql.NullString{String: search, Valid: true}
|
||||
@@ -99,15 +89,9 @@ func handleGetProjects(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
totalCount := int(total)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"projects": projects,
|
||||
"pagination": gin.H{
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
"total": totalCount,
|
||||
"pages": (totalCount + limit - 1) / limit,
|
||||
},
|
||||
"projects": projects,
|
||||
"pagination": paginationMeta(offset, limit, int(total)),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user