build: /design-feature add-hello-endpoint
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
parent
de474b5e44
commit
7d9eafbb43
201
.sdlc/features/add-hello-endpoint/design.md
Normal file
201
.sdlc/features/add-hello-endpoint/design.md
Normal file
@ -0,0 +1,201 @@
|
||||
# Design: Add /hello Endpoint to API Service
|
||||
|
||||
## Architecture Approach
|
||||
|
||||
This is a minimal addition that follows existing patterns exactly. No new architectural components are introduced.
|
||||
|
||||
**Layers changed:**
|
||||
- `services/api/internal/api/handlers/` - New `hello.go` handler file
|
||||
- `services/api/internal/api/routes.go` - Route registration
|
||||
- `services/api/internal/api/spec.go` - OpenAPI documentation
|
||||
|
||||
**Approach:** Create a standalone handler struct with a single `Say` method that returns a greeting. The handler follows the error-returning pattern used by `Example` handler (not the direct `http.HandlerFunc` pattern used by `Health`), allowing for consistent error handling if we add complexity later.
|
||||
|
||||
## Data Model Changes
|
||||
|
||||
**No database or schema changes required.**
|
||||
|
||||
Response structure (uses existing envelope):
|
||||
```go
|
||||
// HelloResponse is the data returned by GET /api/v1/hello
|
||||
type HelloResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
```
|
||||
|
||||
Envelope output:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"message": "Hello, World!"
|
||||
},
|
||||
"meta": {
|
||||
"request_id": "abc123",
|
||||
"timestamp": "2026-02-03T12:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Changes
|
||||
|
||||
### New Endpoint
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/api/v1/hello` | None | Returns greeting message |
|
||||
|
||||
### Request
|
||||
|
||||
No request body or parameters.
|
||||
|
||||
### Response
|
||||
|
||||
**Success (200 OK):**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"message": "Hello, World!"
|
||||
},
|
||||
"meta": {
|
||||
"request_id": "...",
|
||||
"timestamp": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Component Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ HTTP Request │
|
||||
│ GET /api/v1/hello │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Chi Router (routes.go) │
|
||||
│ │
|
||||
│ r.Get("/hello", app.Wrap(helloHandler.Say)) │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Middleware Stack │
|
||||
│ [RequestID] → [CORS] → [Recovery] → [Logger] │
|
||||
│ (Already configured in app.App) │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ app.Wrap() │
|
||||
│ Converts error-returning handler to http.HandlerFunc │
|
||||
│ Maps HTTPError → status code, other errors → 500 │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ handlers/hello.go │
|
||||
│ │
|
||||
│ func (h *Hello) Say(w, r) error { │
|
||||
│ httpresponse.OK(w, r, HelloResponse{ │
|
||||
│ Message: "Hello, World!", │
|
||||
│ }) │
|
||||
│ return nil │
|
||||
│ } │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ httpresponse.OK() │
|
||||
│ Wraps data in {data, meta} envelope │
|
||||
│ Adds request_id and timestamp to meta │
|
||||
│ Sets Content-Type: application/json │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ HTTP Response │
|
||||
│ 200 OK │
|
||||
│ {"data": {"message": "Hello, World!"}, "meta": ...} │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Error Handling Strategy
|
||||
|
||||
This endpoint has minimal failure modes:
|
||||
|
||||
| Scenario | Handling | Response |
|
||||
|----------|----------|----------|
|
||||
| Normal request | Return greeting | 200 with `{data, meta}` |
|
||||
| Middleware panic | Recovery middleware catches | 500 with generic error |
|
||||
| JSON encoding failure | Caught by `httpresponse.OK` | 500 internal error |
|
||||
|
||||
Since this handler:
|
||||
- Takes no input (no validation errors possible)
|
||||
- Makes no external calls (no timeout/network errors)
|
||||
- Has no authorization (no auth errors possible)
|
||||
|
||||
The only realistic failure mode is a panic in the middleware stack, which is already handled by the Recovery middleware.
|
||||
|
||||
**Decision:** Use error-returning handler pattern (`app.Wrap`) for consistency with other handlers, even though this specific handler always returns `nil`. This makes future extension easier if we add features like parameterized greetings.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
| Concern | Mitigation |
|
||||
|---------|------------|
|
||||
| **Authentication** | Endpoint is intentionally public (no auth required) |
|
||||
| **Authorization** | No protected resources accessed |
|
||||
| **Input validation** | No input accepted (GET with no params/body) |
|
||||
| **Data exposure** | Only static string returned, no sensitive data |
|
||||
| **Rate limiting** | Uses global rate limiting if configured (out of scope for this feature) |
|
||||
| **CORS** | Uses existing CORS middleware configuration |
|
||||
|
||||
**Risk assessment:** Low risk. This is a read-only endpoint returning static content with no user input and no sensitive data.
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
| Aspect | Analysis |
|
||||
|--------|----------|
|
||||
| **Expected load** | Low - primarily used for connectivity checks |
|
||||
| **Response time** | Sub-millisecond (no I/O, no computation) |
|
||||
| **Memory** | Negligible - single small response struct |
|
||||
| **Caching** | Not needed - response is static and fast to generate |
|
||||
| **Connection pooling** | N/A - no database or external calls |
|
||||
|
||||
**Optimization:** None required. The endpoint is already optimal by design.
|
||||
|
||||
## Migration / Rollout Plan
|
||||
|
||||
**Zero-downtime deployment:** This is a purely additive change.
|
||||
|
||||
1. **No migration needed** - No database changes
|
||||
2. **No feature flags needed** - Endpoint is stateless and low-risk
|
||||
3. **No backwards compatibility concerns** - New endpoint, no existing consumers
|
||||
|
||||
**Rollout steps:**
|
||||
1. Deploy code changes (handler, routes, spec)
|
||||
2. Verify endpoint responds at `/api/v1/hello`
|
||||
3. Verify OpenAPI spec includes new endpoint at `/docs`
|
||||
|
||||
**Rollback:** Standard deployment rollback if issues arise (no data cleanup needed).
|
||||
|
||||
## File Changes Summary
|
||||
|
||||
| File | Change Type | Description |
|
||||
|------|-------------|-------------|
|
||||
| `services/api/internal/api/handlers/hello.go` | New | Handler struct and Say method |
|
||||
| `services/api/internal/api/handlers/hello_test.go` | New | Unit tests for handler |
|
||||
| `services/api/internal/api/routes.go` | Modify | Register GET /api/v1/hello route |
|
||||
| `services/api/internal/api/spec.go` | Modify | Add Hello tag and /hello path |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
1. **Handler location:** Create `handlers/hello.go` alongside existing handlers rather than adding to `health.go` - the spec recommends a dedicated "Hello" tag to distinguish from infrastructure health checks.
|
||||
|
||||
2. **Response type:** Define `HelloResponse` in the handler file (not a separate types file) since it's only used by this handler.
|
||||
|
||||
3. **Route registration:** Add `helloHandler` initialization in `RegisterRoutes` and register route in the public routes section (outside the auth group).
|
||||
|
||||
4. **OpenAPI tag:** Add `"Hello"` tag with description `"Simple greeting endpoint"` to differentiate from Health endpoints.
|
||||
|
||||
5. **Test pattern:** Follow `example_test.go` pattern with table-driven tests, though a single happy-path test is sufficient for this simple endpoint.
|
||||
@ -7,6 +7,10 @@
|
||||
"spec": {
|
||||
"status": "approved",
|
||||
"approvedAt": "2026-02-03T03:00:00Z"
|
||||
},
|
||||
"design": {
|
||||
"status": "draft",
|
||||
"createdAt": "2026-02-03T03:02:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user