init
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
// Package api holds the wire format shared by pages-server and the pages CLI.
|
||||
//
|
||||
// It must depend on the standard library only. cmd/pages imports this package,
|
||||
// and cmd/pages/deps_test.go fails the build if any server-side dependency
|
||||
// (SQLite driver, database/sql, internal/store, ...) reaches the CLI through it.
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Code is a machine-readable error code. Clients switch on these; the
|
||||
// accompanying message is for humans and may change.
|
||||
type Code string
|
||||
|
||||
const (
|
||||
CodeBadRequest Code = "bad_request"
|
||||
CodeUnauthorized Code = "unauthorized"
|
||||
CodeForbidden Code = "forbidden"
|
||||
CodeNotFound Code = "not_found"
|
||||
CodeMethodNotAllowed Code = "method_not_allowed"
|
||||
CodeConflict Code = "conflict"
|
||||
CodePayloadTooLarge Code = "payload_too_large"
|
||||
CodeRateLimited Code = "rate_limited"
|
||||
CodeInternal Code = "internal"
|
||||
CodeUnavailable Code = "unavailable"
|
||||
|
||||
// Domain-specific codes.
|
||||
CodeProjectExists Code = "project_exists"
|
||||
CodeInvalidProjectName Code = "invalid_project_name"
|
||||
CodeInvalidPath Code = "invalid_path"
|
||||
CodeDigestMismatch Code = "digest_mismatch"
|
||||
CodeSizeMismatch Code = "size_mismatch"
|
||||
CodeDeploymentNotReady Code = "deployment_not_ready"
|
||||
CodeDeploymentActive Code = "deployment_active"
|
||||
CodeBlobsMissing Code = "blobs_missing"
|
||||
CodeLimitExceeded Code = "limit_exceeded"
|
||||
)
|
||||
|
||||
// Error is the body of every non-2xx management API response:
|
||||
//
|
||||
// {"error":{"code":"deployment_not_ready","message":"...","details":{...}}}
|
||||
type Error struct {
|
||||
Code Code `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Details map[string]any `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// ErrorEnvelope wraps Error so the JSON has a single top-level "error" key.
|
||||
type ErrorEnvelope struct {
|
||||
Error Error `json:"error"`
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.Message == "" {
|
||||
return string(e.Code)
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// Errorf builds an *Error with a formatted message.
|
||||
func Errorf(code Code, format string, args ...any) *Error {
|
||||
return &Error{Code: code, Message: fmt.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
// WithDetail attaches a detail key and returns the receiver for chaining.
|
||||
func (e *Error) WithDetail(key string, val any) *Error {
|
||||
if e.Details == nil {
|
||||
e.Details = make(map[string]any, 1)
|
||||
}
|
||||
e.Details[key] = val
|
||||
return e
|
||||
}
|
||||
|
||||
// CodeOf reports the Code carried by err, or CodeInternal when err is not an
|
||||
// *Error. It unwraps, so a wrapped *Error is still recognised.
|
||||
func CodeOf(err error) Code {
|
||||
var apiErr *Error
|
||||
if errors.As(err, &apiErr) {
|
||||
return apiErr.Code
|
||||
}
|
||||
return CodeInternal
|
||||
}
|
||||
Reference in New Issue
Block a user