build: /design-feature add-hello-endpoint
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
rdev-worker 2026-02-03 03:04:46 +00:00
parent de474b5e44
commit 7d9eafbb43
2 changed files with 205 additions and 0 deletions

View 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.

View File

@ -7,6 +7,10 @@
"spec": { "spec": {
"status": "approved", "status": "approved",
"approvedAt": "2026-02-03T03:00:00Z" "approvedAt": "2026-02-03T03:00:00Z"
},
"design": {
"status": "draft",
"createdAt": "2026-02-03T03:02:00Z"
} }
} }
} }