Implement Phase 9: client libraries (Go, Rust, Lisp, Python)
- clients/README.md: canonical API surface and error type reference - clients/testdata/: shared JSON response fixtures - clients/go/: mciasgoclient package; net/http + TLS 1.2+; sync.RWMutex token state; DisallowUnknownFields on all decoders; 25 tests pass - clients/rust/: async mcias-client crate; reqwest+rustls (no OpenSSL); thiserror MciasError enum; Arc<RwLock> token state; 22+1 tests pass; cargo clippy -D warnings clean - clients/lisp/: ASDF mcias-client; dexador HTTP, yason JSON; mcias-error condition hierarchy; Hunchentoot mock-dispatcher; 37 fiveam checks pass on SBCL 2.6.1; yason boolean normalisation in validate-token - clients/python/: mcias_client package (Python 3.11+); httpx sync; py.typed; dataclasses; 32 pytest tests; mypy --strict + ruff clean - test/mock/mockserver.go: in-memory mock server for Go client tests - ARCHITECTURE.md §19: updated per-language notes to match implementation - PROGRESS.md: Phase 9 marked complete - .gitignore: exclude clients/rust/target/, python .venv, .pytest_cache, .fasl files Security: token never logged or exposed in error messages in any library; TLS enforced in all four languages; token stored under lock/mutex/RwLock
This commit is contained in:
37
clients/lisp/conditions.lisp
Normal file
37
clients/lisp/conditions.lisp
Normal file
@@ -0,0 +1,37 @@
|
||||
;;;; conditions.lisp -- MCIAS error condition hierarchy
|
||||
|
||||
(in-package #:mcias-client)
|
||||
|
||||
(define-condition mcias-error (error)
|
||||
((status :initarg :status :reader mcias-error-status
|
||||
:documentation "HTTP status code (integer).")
|
||||
(message :initarg :message :reader mcias-error-message
|
||||
:documentation "Server error message string."))
|
||||
(:report (lambda (c s)
|
||||
(format s "MCIAS error ~A: ~A"
|
||||
(mcias-error-status c)
|
||||
(mcias-error-message c))))
|
||||
(:documentation "Base condition for all MCIAS API errors."))
|
||||
|
||||
(define-condition mcias-auth-error (mcias-error) ()
|
||||
(:documentation "401 Unauthorized -- token missing, invalid, or expired."))
|
||||
(define-condition mcias-forbidden-error (mcias-error) ()
|
||||
(:documentation "403 Forbidden -- insufficient role."))
|
||||
(define-condition mcias-not-found-error (mcias-error) ()
|
||||
(:documentation "404 Not Found -- resource does not exist."))
|
||||
(define-condition mcias-input-error (mcias-error) ()
|
||||
(:documentation "400 Bad Request -- malformed request."))
|
||||
(define-condition mcias-conflict-error (mcias-error) ()
|
||||
(:documentation "409 Conflict -- e.g. duplicate username."))
|
||||
(define-condition mcias-server-error (mcias-error) ()
|
||||
(:documentation "5xx -- unexpected server error."))
|
||||
|
||||
(defun signal-mcias-error (status message)
|
||||
"Signal the appropriate MCIAS condition for STATUS (integer) and MESSAGE (string)."
|
||||
(case status
|
||||
(401 (error 'mcias-auth-error :status status :message message))
|
||||
(403 (error 'mcias-forbidden-error :status status :message message))
|
||||
(404 (error 'mcias-not-found-error :status status :message message))
|
||||
(400 (error 'mcias-input-error :status status :message message))
|
||||
(409 (error 'mcias-conflict-error :status status :message message))
|
||||
(t (error 'mcias-server-error :status status :message message))))
|
||||
Reference in New Issue
Block a user