@mytechtoday/augment-extensions 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/augment-extensions/coding-standards/c/CHANGELOG.md +55 -0
- package/augment-extensions/coding-standards/c/LICENSE +22 -0
- package/augment-extensions/coding-standards/c/README.md +167 -0
- package/augment-extensions/coding-standards/c/config/defaults.json +26 -0
- package/augment-extensions/coding-standards/c/config/examples/embedded.yaml +25 -0
- package/augment-extensions/coding-standards/c/config/examples/systems.json +31 -0
- package/augment-extensions/coding-standards/c/config/schema.json +244 -0
- package/augment-extensions/coding-standards/c/docs/API.md +613 -0
- package/augment-extensions/coding-standards/c/docs/CONFIGURATION.md +259 -0
- package/augment-extensions/coding-standards/c/docs/USER_GUIDE.md +567 -0
- package/augment-extensions/coding-standards/c/examples/drivers/Makefile +33 -0
- package/augment-extensions/coding-standards/c/examples/drivers/README.md +192 -0
- package/augment-extensions/coding-standards/c/examples/drivers/dma-example.c +224 -0
- package/augment-extensions/coding-standards/c/examples/drivers/example.dts +64 -0
- package/augment-extensions/coding-standards/c/examples/drivers/platform-driver.c +174 -0
- package/augment-extensions/coding-standards/c/examples/embedded/README.md +167 -0
- package/augment-extensions/coding-standards/c/examples/embedded/gpio-control.c +172 -0
- package/augment-extensions/coding-standards/c/examples/embedded/timer-isr.c +198 -0
- package/augment-extensions/coding-standards/c/examples/embedded/uart-communication.c +212 -0
- package/augment-extensions/coding-standards/c/examples/kernel/Makefile +82 -0
- package/augment-extensions/coding-standards/c/examples/kernel/README.md +168 -0
- package/augment-extensions/coding-standards/c/examples/kernel/char-device.c +198 -0
- package/augment-extensions/coding-standards/c/examples/kernel/proc-file.c +131 -0
- package/augment-extensions/coding-standards/c/examples/kernel/simple-module.c +111 -0
- package/augment-extensions/coding-standards/c/examples/legacy/Makefile +62 -0
- package/augment-extensions/coding-standards/c/examples/legacy/README.md +255 -0
- package/augment-extensions/coding-standards/c/examples/legacy/c89-to-c11-migration.c +268 -0
- package/augment-extensions/coding-standards/c/examples/legacy/compatibility-layer.c +239 -0
- package/augment-extensions/coding-standards/c/examples/networking/Makefile +35 -0
- package/augment-extensions/coding-standards/c/examples/networking/README.md +207 -0
- package/augment-extensions/coding-standards/c/examples/networking/protocol-parser.c +270 -0
- package/augment-extensions/coding-standards/c/examples/networking/tcp-server.c +197 -0
- package/augment-extensions/coding-standards/c/examples/networking/udp-multicast.c +220 -0
- package/augment-extensions/coding-standards/c/examples/realtime/Makefile +53 -0
- package/augment-extensions/coding-standards/c/examples/realtime/README.md +199 -0
- package/augment-extensions/coding-standards/c/examples/realtime/deadline-monitoring.c +260 -0
- package/augment-extensions/coding-standards/c/examples/realtime/priority-scheduling.c +258 -0
- package/augment-extensions/coding-standards/c/examples/systems/Makefile +34 -0
- package/augment-extensions/coding-standards/c/examples/systems/README.md +123 -0
- package/augment-extensions/coding-standards/c/examples/systems/ipc-pipes.c +181 -0
- package/augment-extensions/coding-standards/c/examples/systems/process-management.c +153 -0
- package/augment-extensions/coding-standards/c/examples/systems/signal-handling.c +162 -0
- package/augment-extensions/coding-standards/c/module.json +149 -0
- package/augment-extensions/coding-standards/c/rules/categories/drivers.md +635 -0
- package/augment-extensions/coding-standards/c/rules/categories/embedded.md +510 -0
- package/augment-extensions/coding-standards/c/rules/categories/kernel.md +653 -0
- package/augment-extensions/coding-standards/c/rules/categories/legacy.md +526 -0
- package/augment-extensions/coding-standards/c/rules/categories/networking.md +735 -0
- package/augment-extensions/coding-standards/c/rules/categories/realtime.md +631 -0
- package/augment-extensions/coding-standards/c/rules/categories/systems.md +586 -0
- package/augment-extensions/coding-standards/c/rules/universal/const-correctness.md +275 -0
- package/augment-extensions/coding-standards/c/rules/universal/documentation.md +251 -0
- package/augment-extensions/coding-standards/c/rules/universal/error-handling.md +250 -0
- package/augment-extensions/coding-standards/c/rules/universal/header-guards.md +254 -0
- package/augment-extensions/coding-standards/c/rules/universal/memory-safety.md +233 -0
- package/augment-extensions/coding-standards/c/rules/universal/naming.md +146 -0
- package/augment-extensions/coding-standards/c/src/conflict-detector.ts +461 -0
- package/augment-extensions/coding-standards/c/src/prompt-generator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-evaluator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-override.ts +427 -0
- package/augment-extensions/coding-standards/c/src/template-engine.ts +217 -0
- package/augment-extensions/coding-standards/c/templates/prompts/drivers.txt +191 -0
- package/augment-extensions/coding-standards/c/templates/prompts/embedded.txt +164 -0
- package/augment-extensions/coding-standards/c/templates/prompts/kernel.txt +175 -0
- package/augment-extensions/coding-standards/c/templates/prompts/legacy.txt +280 -0
- package/augment-extensions/coding-standards/c/templates/prompts/networking.txt +259 -0
- package/augment-extensions/coding-standards/c/templates/prompts/realtime.txt +219 -0
- package/augment-extensions/coding-standards/c/templates/prompts/systems.txt +147 -0
- package/augment-extensions/coding-standards/c/tests/integration/category-specific.test.ts +356 -0
- package/augment-extensions/coding-standards/c/tests/integration/end-to-end-workflow.test.ts +377 -0
- package/augment-extensions/coding-standards/c/tests/performance/benchmarks.test.ts +407 -0
- package/augment-extensions/coding-standards/c/tests/unit/config-manager.test.ts +345 -0
- package/augment-extensions/coding-standards/c/tests/unit/conflict-detector.test.ts +294 -0
- package/augment-extensions/coding-standards/c/tests/unit/prompt-generator.test.ts +174 -0
- package/augment-extensions/coding-standards/c/tests/unit/registry.test.ts +313 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-evaluator.test.ts +318 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-override.test.ts +326 -0
- package/augment-extensions/coding-standards/c/tests/unit/template-engine.test.ts +314 -0
- package/augment-extensions/coding-standards/go/CHARACTER-COUNT-REPORT.md +135 -0
- package/augment-extensions/coding-standards/go/PHASE1-COMPLETION.md +146 -0
- package/augment-extensions/coding-standards/go/PHASE4-COMPLETION.md +184 -0
- package/augment-extensions/coding-standards/go/README.md +200 -0
- package/augment-extensions/coding-standards/go/VALIDATION-CHECKLIST.md +154 -0
- package/augment-extensions/coding-standards/go/config/examples/example-cli.json +15 -0
- package/augment-extensions/coding-standards/go/config/examples/example-microservices.json +21 -0
- package/augment-extensions/coding-standards/go/config/examples/example-multi-category.yaml +24 -0
- package/augment-extensions/coding-standards/go/config/examples/example-web.json +15 -0
- package/augment-extensions/coding-standards/go/config/schema.json +110 -0
- package/augment-extensions/coding-standards/go/docs/CATEGORIES.md +221 -0
- package/augment-extensions/coding-standards/go/docs/CONFIGURATION.md +198 -0
- package/augment-extensions/coding-standards/go/docs/TROUBLESHOOTING.md +285 -0
- package/augment-extensions/coding-standards/go/examples/cli/cobra-app.go +287 -0
- package/augment-extensions/coding-standards/go/examples/cloud-native-app.go +217 -0
- package/augment-extensions/coding-standards/go/examples/devops-tool.go +250 -0
- package/augment-extensions/coding-standards/go/examples/distributed-system.go +247 -0
- package/augment-extensions/coding-standards/go/examples/microservices/grpc-service.go +253 -0
- package/augment-extensions/coding-standards/go/examples/rest-api.go +270 -0
- package/augment-extensions/coding-standards/go/examples/web/http-server.go +224 -0
- package/augment-extensions/coding-standards/go/module.json +139 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/api-versioning.md +149 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rate-limiting.md +209 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rest-api-design.md +183 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/cloud-config.md +193 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/health-checks.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/kubernetes.md +180 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/automation.md +179 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/ci-cd-integration.md +147 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/infrastructure-as-code.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/caching.md +150 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/consensus.md +187 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/event-sourcing.md +246 -0
- package/augment-extensions/coding-standards/go/rules/cli/command-parsing.md +264 -0
- package/augment-extensions/coding-standards/go/rules/cli/configuration.md +268 -0
- package/augment-extensions/coding-standards/go/rules/cli/cross-platform.md +324 -0
- package/augment-extensions/coding-standards/go/rules/microservices/distributed-tracing.md +253 -0
- package/augment-extensions/coding-standards/go/rules/microservices/grpc.md +257 -0
- package/augment-extensions/coding-standards/go/rules/microservices/metrics.md +278 -0
- package/augment-extensions/coding-standards/go/rules/microservices/service-discovery.md +249 -0
- package/augment-extensions/coding-standards/go/rules/universal/code-organization.md +221 -0
- package/augment-extensions/coding-standards/go/rules/universal/documentation.md +269 -0
- package/augment-extensions/coding-standards/go/rules/universal/performance.md +323 -0
- package/augment-extensions/coding-standards/go/rules/universal/testing.md +162 -0
- package/augment-extensions/coding-standards/go/rules/web/graceful-shutdown.md +249 -0
- package/augment-extensions/coding-standards/go/rules/web/http-handlers.md +164 -0
- package/augment-extensions/coding-standards/go/rules/web/middleware.md +234 -0
- package/augment-extensions/coding-standards/go/rules/web/routing.md +251 -0
- package/augment-extensions/coding-standards/go/templates/prompts/api.md +160 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cli.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cloud-native.md +121 -0
- package/augment-extensions/coding-standards/go/templates/prompts/devops.md +146 -0
- package/augment-extensions/coding-standards/go/templates/prompts/distributed.md +133 -0
- package/augment-extensions/coding-standards/go/templates/prompts/microservices.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/web.md +181 -0
- package/augment-extensions/coding-standards/go/tests/integration/module-integration.test.ts +164 -0
- package/augment-extensions/coding-standards/go/tests/unit/category-selection.test.ts +147 -0
- package/augment-extensions/coding-standards/go/tests/unit/module-structure.test.ts +154 -0
- package/augment-extensions/coding-standards/go/tests/validate-character-count.ps1 +13 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.ps1 +148 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.sh +135 -0
- package/cli/dist/analysis/ast-parser.d.ts +47 -0
- package/cli/dist/analysis/ast-parser.d.ts.map +1 -0
- package/cli/dist/analysis/ast-parser.js +161 -0
- package/cli/dist/analysis/ast-parser.js.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts +27 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.js +189 -0
- package/cli/dist/analysis/complexity-analyzer.js.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts +23 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.js +237 -0
- package/cli/dist/analysis/dependency-analyzer.js.map +1 -0
- package/cli/dist/analysis/index.d.ts +9 -0
- package/cli/dist/analysis/index.d.ts.map +1 -0
- package/cli/dist/analysis/index.js +25 -0
- package/cli/dist/analysis/index.js.map +1 -0
- package/cli/dist/analysis/security-scanner.d.ts +11 -0
- package/cli/dist/analysis/security-scanner.d.ts.map +1 -0
- package/cli/dist/analysis/security-scanner.js +294 -0
- package/cli/dist/analysis/security-scanner.js.map +1 -0
- package/cli/dist/analysis/types.d.ts +151 -0
- package/cli/dist/analysis/types.d.ts.map +1 -0
- package/cli/dist/analysis/types.js +6 -0
- package/cli/dist/analysis/types.js.map +1 -0
- package/cli/dist/cli.js +24 -0
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/code-analysis.d.ts +11 -0
- package/cli/dist/commands/code-analysis.d.ts.map +1 -0
- package/cli/dist/commands/code-analysis.js +412 -0
- package/cli/dist/commands/code-analysis.js.map +1 -0
- package/modules.md +99 -3
- package/package.json +14 -2
- package/cli/dist/commands/agent.d.ts +0 -37
- package/cli/dist/commands/agent.d.ts.map +0 -1
- package/cli/dist/commands/agent.js +0 -222
- package/cli/dist/commands/agent.js.map +0 -1
- package/cli/dist/commands/beads.d.ts +0 -64
- package/cli/dist/commands/beads.d.ts.map +0 -1
- package/cli/dist/commands/beads.js +0 -377
- package/cli/dist/commands/beads.js.map +0 -1
- package/cli/dist/commands/change.d.ts +0 -54
- package/cli/dist/commands/change.d.ts.map +0 -1
- package/cli/dist/commands/change.js +0 -243
- package/cli/dist/commands/change.js.map +0 -1
- package/cli/dist/commands/clean.d.ts +0 -15
- package/cli/dist/commands/clean.d.ts.map +0 -1
- package/cli/dist/commands/clean.js +0 -63
- package/cli/dist/commands/clean.js.map +0 -1
- package/cli/dist/commands/clone.d.ts +0 -15
- package/cli/dist/commands/clone.d.ts.map +0 -1
- package/cli/dist/commands/clone.js +0 -49
- package/cli/dist/commands/clone.js.map +0 -1
- package/cli/dist/commands/config.d.ts +0 -33
- package/cli/dist/commands/config.d.ts.map +0 -1
- package/cli/dist/commands/config.js +0 -166
- package/cli/dist/commands/config.js.map +0 -1
- package/cli/dist/commands/context.d.ts +0 -38
- package/cli/dist/commands/context.d.ts.map +0 -1
- package/cli/dist/commands/context.js +0 -205
- package/cli/dist/commands/context.js.map +0 -1
- package/cli/dist/commands/create.d.ts +0 -18
- package/cli/dist/commands/create.d.ts.map +0 -1
- package/cli/dist/commands/create.js +0 -178
- package/cli/dist/commands/create.js.map +0 -1
- package/cli/dist/commands/diff.d.ts +0 -19
- package/cli/dist/commands/diff.d.ts.map +0 -1
- package/cli/dist/commands/diff.js +0 -104
- package/cli/dist/commands/diff.js.map +0 -1
- package/cli/dist/commands/doctor.d.ts +0 -14
- package/cli/dist/commands/doctor.d.ts.map +0 -1
- package/cli/dist/commands/doctor.js +0 -62
- package/cli/dist/commands/doctor.js.map +0 -1
- package/cli/dist/commands/export.d.ts +0 -28
- package/cli/dist/commands/export.d.ts.map +0 -1
- package/cli/dist/commands/export.js +0 -135
- package/cli/dist/commands/export.js.map +0 -1
- package/cli/dist/commands/import.d.ts +0 -23
- package/cli/dist/commands/import.d.ts.map +0 -1
- package/cli/dist/commands/import.js +0 -118
- package/cli/dist/commands/import.js.map +0 -1
- package/cli/dist/commands/prompt.d.ts +0 -45
- package/cli/dist/commands/prompt.d.ts.map +0 -1
- package/cli/dist/commands/prompt.js +0 -223
- package/cli/dist/commands/prompt.js.map +0 -1
- package/cli/dist/commands/spec.d.ts +0 -57
- package/cli/dist/commands/spec.d.ts.map +0 -1
- package/cli/dist/commands/spec.js +0 -279
- package/cli/dist/commands/spec.js.map +0 -1
- package/cli/dist/commands/stats.d.ts +0 -18
- package/cli/dist/commands/stats.d.ts.map +0 -1
- package/cli/dist/commands/stats.js +0 -85
- package/cli/dist/commands/stats.js.map +0 -1
- package/cli/dist/commands/task.d.ts +0 -65
- package/cli/dist/commands/task.d.ts.map +0 -1
- package/cli/dist/commands/task.js +0 -282
- package/cli/dist/commands/task.js.map +0 -1
- package/cli/dist/commands/template.d.ts +0 -17
- package/cli/dist/commands/template.d.ts.map +0 -1
- package/cli/dist/commands/template.js +0 -55
- package/cli/dist/commands/template.js.map +0 -1
- package/cli/dist/utils/agent-config.d.ts +0 -129
- package/cli/dist/utils/agent-config.d.ts.map +0 -1
- package/cli/dist/utils/agent-config.js +0 -297
- package/cli/dist/utils/agent-config.js.map +0 -1
- package/cli/dist/utils/beads-graph.d.ts +0 -17
- package/cli/dist/utils/beads-graph.d.ts.map +0 -1
- package/cli/dist/utils/beads-graph.js +0 -150
- package/cli/dist/utils/beads-graph.js.map +0 -1
- package/cli/dist/utils/beads-integration.d.ts +0 -112
- package/cli/dist/utils/beads-integration.d.ts.map +0 -1
- package/cli/dist/utils/beads-integration.js +0 -312
- package/cli/dist/utils/beads-integration.js.map +0 -1
- package/cli/dist/utils/beads-reporter.d.ts +0 -17
- package/cli/dist/utils/beads-reporter.d.ts.map +0 -1
- package/cli/dist/utils/beads-reporter.js +0 -160
- package/cli/dist/utils/beads-reporter.js.map +0 -1
- package/cli/dist/utils/cache-manager.d.ts +0 -55
- package/cli/dist/utils/cache-manager.d.ts.map +0 -1
- package/cli/dist/utils/cache-manager.js +0 -150
- package/cli/dist/utils/cache-manager.js.map +0 -1
- package/cli/dist/utils/change-manager.d.ts +0 -70
- package/cli/dist/utils/change-manager.d.ts.map +0 -1
- package/cli/dist/utils/change-manager.js +0 -412
- package/cli/dist/utils/change-manager.js.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.d.ts +0 -66
- package/cli/dist/utils/config-manager-enhanced.d.ts.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.js +0 -77
- package/cli/dist/utils/config-manager-enhanced.js.map +0 -1
- package/cli/dist/utils/context-manager.d.ts +0 -96
- package/cli/dist/utils/context-manager.d.ts.map +0 -1
- package/cli/dist/utils/context-manager.js +0 -258
- package/cli/dist/utils/context-manager.js.map +0 -1
- package/cli/dist/utils/diff-engine.d.ts +0 -78
- package/cli/dist/utils/diff-engine.d.ts.map +0 -1
- package/cli/dist/utils/diff-engine.js +0 -233
- package/cli/dist/utils/diff-engine.js.map +0 -1
- package/cli/dist/utils/export-system.d.ts +0 -101
- package/cli/dist/utils/export-system.d.ts.map +0 -1
- package/cli/dist/utils/export-system.js +0 -289
- package/cli/dist/utils/export-system.js.map +0 -1
- package/cli/dist/utils/health-checker.d.ts +0 -66
- package/cli/dist/utils/health-checker.d.ts.map +0 -1
- package/cli/dist/utils/health-checker.js +0 -285
- package/cli/dist/utils/health-checker.js.map +0 -1
- package/cli/dist/utils/import-system.d.ts +0 -74
- package/cli/dist/utils/import-system.d.ts.map +0 -1
- package/cli/dist/utils/import-system.js +0 -317
- package/cli/dist/utils/import-system.js.map +0 -1
- package/cli/dist/utils/module-cloner.d.ts +0 -40
- package/cli/dist/utils/module-cloner.d.ts.map +0 -1
- package/cli/dist/utils/module-cloner.js +0 -136
- package/cli/dist/utils/module-cloner.js.map +0 -1
- package/cli/dist/utils/prompt-manager.d.ts +0 -90
- package/cli/dist/utils/prompt-manager.d.ts.map +0 -1
- package/cli/dist/utils/prompt-manager.js +0 -302
- package/cli/dist/utils/prompt-manager.js.map +0 -1
- package/cli/dist/utils/spec-manager.d.ts +0 -65
- package/cli/dist/utils/spec-manager.d.ts.map +0 -1
- package/cli/dist/utils/spec-manager.js +0 -329
- package/cli/dist/utils/spec-manager.js.map +0 -1
- package/cli/dist/utils/stats-collector.d.ts +0 -74
- package/cli/dist/utils/stats-collector.d.ts.map +0 -1
- package/cli/dist/utils/stats-collector.js +0 -164
- package/cli/dist/utils/stats-collector.js.map +0 -1
- package/cli/dist/utils/template-engine.d.ts +0 -47
- package/cli/dist/utils/template-engine.d.ts.map +0 -1
- package/cli/dist/utils/template-engine.js +0 -204
- package/cli/dist/utils/template-engine.js.map +0 -1
package/augment-extensions/coding-standards/go/rules/categories/api-development/rate-limiting.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Rate Limiting Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for implementing rate limiting in Go REST APIs to prevent abuse and ensure fair resource usage.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Implement Token Bucket Algorithm
|
|
10
|
+
|
|
11
|
+
**Rule**: Use token bucket algorithm for smooth rate limiting.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
import "golang.org/x/time/rate"
|
|
16
|
+
|
|
17
|
+
type RateLimiter struct {
|
|
18
|
+
limiters map[string]*rate.Limiter
|
|
19
|
+
mu sync.RWMutex
|
|
20
|
+
rate rate.Limit
|
|
21
|
+
burst int
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func NewRateLimiter(r rate.Limit, b int) *RateLimiter {
|
|
25
|
+
return &RateLimiter{
|
|
26
|
+
limiters: make(map[string]*rate.Limiter),
|
|
27
|
+
rate: r,
|
|
28
|
+
burst: b,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func (rl *RateLimiter) GetLimiter(key string) *rate.Limiter {
|
|
33
|
+
rl.mu.Lock()
|
|
34
|
+
defer rl.mu.Unlock()
|
|
35
|
+
|
|
36
|
+
limiter, exists := rl.limiters[key]
|
|
37
|
+
if !exists {
|
|
38
|
+
limiter = rate.NewLimiter(rl.rate, rl.burst)
|
|
39
|
+
rl.limiters[key] = limiter
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return limiter
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Return Rate Limit Headers
|
|
47
|
+
|
|
48
|
+
**Rule**: Include rate limit information in response headers.
|
|
49
|
+
|
|
50
|
+
**Good Example**:
|
|
51
|
+
```go
|
|
52
|
+
func RateLimitMiddleware(limiter *RateLimiter) func(http.Handler) http.Handler {
|
|
53
|
+
return func(next http.Handler) http.Handler {
|
|
54
|
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
55
|
+
key := getClientKey(r) // IP or API key
|
|
56
|
+
|
|
57
|
+
l := limiter.GetLimiter(key)
|
|
58
|
+
|
|
59
|
+
if !l.Allow() {
|
|
60
|
+
w.Header().Set("X-RateLimit-Limit", fmt.Sprintf("%d", limiter.burst))
|
|
61
|
+
w.Header().Set("X-RateLimit-Remaining", "0")
|
|
62
|
+
w.Header().Set("X-RateLimit-Reset", fmt.Sprintf("%d", time.Now().Add(time.Minute).Unix()))
|
|
63
|
+
w.Header().Set("Retry-After", "60")
|
|
64
|
+
|
|
65
|
+
writeError(w, http.StatusTooManyRequests, "Rate limit exceeded")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add rate limit headers
|
|
70
|
+
w.Header().Set("X-RateLimit-Limit", fmt.Sprintf("%d", limiter.burst))
|
|
71
|
+
w.Header().Set("X-RateLimit-Remaining", fmt.Sprintf("%d", l.Tokens()))
|
|
72
|
+
|
|
73
|
+
next.ServeHTTP(w, r)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Implement Different Limits for Different Endpoints
|
|
80
|
+
|
|
81
|
+
**Rule**: Apply different rate limits based on endpoint sensitivity.
|
|
82
|
+
|
|
83
|
+
**Good Example**:
|
|
84
|
+
```go
|
|
85
|
+
type EndpointLimits struct {
|
|
86
|
+
limiters map[string]*RateLimiter
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func NewEndpointLimits() *EndpointLimits {
|
|
90
|
+
return &EndpointLimits{
|
|
91
|
+
limiters: map[string]*RateLimiter{
|
|
92
|
+
"/api/v1/auth/login": NewRateLimiter(rate.Limit(5), 10), // 5 req/sec
|
|
93
|
+
"/api/v1/users": NewRateLimiter(rate.Limit(100), 200), // 100 req/sec
|
|
94
|
+
"/api/v1/search": NewRateLimiter(rate.Limit(10), 20), // 10 req/sec
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func (el *EndpointLimits) GetLimiter(path string) *RateLimiter {
|
|
100
|
+
if limiter, ok := el.limiters[path]; ok {
|
|
101
|
+
return limiter
|
|
102
|
+
}
|
|
103
|
+
// Default limiter
|
|
104
|
+
return NewRateLimiter(rate.Limit(50), 100)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 4. Support API Key-Based Rate Limiting
|
|
109
|
+
|
|
110
|
+
**Rule**: Implement per-API-key rate limiting for authenticated requests.
|
|
111
|
+
|
|
112
|
+
**Good Example**:
|
|
113
|
+
```go
|
|
114
|
+
type APIKeyLimiter struct {
|
|
115
|
+
limiters map[string]*rate.Limiter
|
|
116
|
+
mu sync.RWMutex
|
|
117
|
+
tiers map[string]RateLimitTier
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type RateLimitTier struct {
|
|
121
|
+
Rate rate.Limit
|
|
122
|
+
Burst int
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
func NewAPIKeyLimiter() *APIKeyLimiter {
|
|
126
|
+
return &APIKeyLimiter{
|
|
127
|
+
limiters: make(map[string]*rate.Limiter),
|
|
128
|
+
tiers: map[string]RateLimitTier{
|
|
129
|
+
"free": {Rate: rate.Limit(10), Burst: 20},
|
|
130
|
+
"basic": {Rate: rate.Limit(100), Burst: 200},
|
|
131
|
+
"premium": {Rate: rate.Limit(1000), Burst: 2000},
|
|
132
|
+
"enterprise": {Rate: rate.Limit(10000), Burst: 20000},
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func (akl *APIKeyLimiter) GetLimiter(apiKey string, tier string) *rate.Limiter {
|
|
138
|
+
akl.mu.Lock()
|
|
139
|
+
defer akl.mu.Unlock()
|
|
140
|
+
|
|
141
|
+
key := fmt.Sprintf("%s:%s", tier, apiKey)
|
|
142
|
+
|
|
143
|
+
limiter, exists := akl.limiters[key]
|
|
144
|
+
if !exists {
|
|
145
|
+
tierConfig := akl.tiers[tier]
|
|
146
|
+
limiter = rate.NewLimiter(tierConfig.Rate, tierConfig.Burst)
|
|
147
|
+
akl.limiters[key] = limiter
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return limiter
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 5. Implement Distributed Rate Limiting
|
|
155
|
+
|
|
156
|
+
**Rule**: Use Redis for rate limiting across multiple servers.
|
|
157
|
+
|
|
158
|
+
**Good Example**:
|
|
159
|
+
```go
|
|
160
|
+
type RedisRateLimiter struct {
|
|
161
|
+
client *redis.Client
|
|
162
|
+
limit int
|
|
163
|
+
window time.Duration
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
func NewRedisRateLimiter(client *redis.Client, limit int, window time.Duration) *RedisRateLimiter {
|
|
167
|
+
return &RedisRateLimiter{
|
|
168
|
+
client: client,
|
|
169
|
+
limit: limit,
|
|
170
|
+
window: window,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
func (rrl *RedisRateLimiter) Allow(ctx context.Context, key string) (bool, error) {
|
|
175
|
+
now := time.Now().Unix()
|
|
176
|
+
windowStart := now - int64(rrl.window.Seconds())
|
|
177
|
+
|
|
178
|
+
pipe := rrl.client.Pipeline()
|
|
179
|
+
|
|
180
|
+
// Remove old entries
|
|
181
|
+
pipe.ZRemRangeByScore(ctx, key, "0", fmt.Sprintf("%d", windowStart))
|
|
182
|
+
|
|
183
|
+
// Count current requests
|
|
184
|
+
countCmd := pipe.ZCard(ctx, key)
|
|
185
|
+
|
|
186
|
+
// Add current request
|
|
187
|
+
pipe.ZAdd(ctx, key, &redis.Z{
|
|
188
|
+
Score: float64(now),
|
|
189
|
+
Member: fmt.Sprintf("%d", now),
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Set expiration
|
|
193
|
+
pipe.Expire(ctx, key, rrl.window)
|
|
194
|
+
|
|
195
|
+
_, err := pipe.Exec(ctx)
|
|
196
|
+
if err != nil {
|
|
197
|
+
return false, err
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
count := countCmd.Val()
|
|
201
|
+
return count < int64(rrl.limit), nil
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## References
|
|
206
|
+
|
|
207
|
+
- [Rate Limiting Algorithms](https://en.wikipedia.org/wiki/Rate_limiting)
|
|
208
|
+
- [golang.org/x/time/rate](https://pkg.go.dev/golang.org/x/time/rate)
|
|
209
|
+
|
package/augment-extensions/coding-standards/go/rules/categories/api-development/rest-api-design.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# REST API Design Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for designing RESTful APIs in Go including resource modeling, HTTP methods, status codes, and response formats.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Proper HTTP Methods
|
|
10
|
+
|
|
11
|
+
**Rule**: Use appropriate HTTP methods for different operations.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
func SetupRoutes(r *mux.Router) {
|
|
16
|
+
// Collection operations
|
|
17
|
+
r.HandleFunc("/api/v1/users", CreateUser).Methods("POST")
|
|
18
|
+
r.HandleFunc("/api/v1/users", ListUsers).Methods("GET")
|
|
19
|
+
|
|
20
|
+
// Resource operations
|
|
21
|
+
r.HandleFunc("/api/v1/users/{id}", GetUser).Methods("GET")
|
|
22
|
+
r.HandleFunc("/api/v1/users/{id}", UpdateUser).Methods("PUT")
|
|
23
|
+
r.HandleFunc("/api/v1/users/{id}", PatchUser).Methods("PATCH")
|
|
24
|
+
r.HandleFunc("/api/v1/users/{id}", DeleteUser).Methods("DELETE")
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Return Appropriate Status Codes
|
|
29
|
+
|
|
30
|
+
**Rule**: Use correct HTTP status codes for different scenarios.
|
|
31
|
+
|
|
32
|
+
**Good Example**:
|
|
33
|
+
```go
|
|
34
|
+
func CreateUser(w http.ResponseWriter, r *http.Request) {
|
|
35
|
+
var user User
|
|
36
|
+
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
|
37
|
+
writeError(w, http.StatusBadRequest, "Invalid request body")
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if err := validateUser(&user); err != nil {
|
|
42
|
+
writeError(w, http.StatusUnprocessableEntity, err.Error())
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if err := db.CreateUser(&user); err != nil {
|
|
47
|
+
if isDuplicateError(err) {
|
|
48
|
+
writeError(w, http.StatusConflict, "User already exists")
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
writeError(w, http.StatusInternalServerError, "Failed to create user")
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
writeJSON(w, http.StatusCreated, user)
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Implement Consistent Error Responses
|
|
60
|
+
|
|
61
|
+
**Rule**: Return structured error responses with consistent format.
|
|
62
|
+
|
|
63
|
+
**Good Example**:
|
|
64
|
+
```go
|
|
65
|
+
type ErrorResponse struct {
|
|
66
|
+
Error string `json:"error"`
|
|
67
|
+
Message string `json:"message"`
|
|
68
|
+
Code string `json:"code,omitempty"`
|
|
69
|
+
Details map[string]string `json:"details,omitempty"`
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func writeError(w http.ResponseWriter, status int, message string) {
|
|
73
|
+
response := ErrorResponse{
|
|
74
|
+
Error: http.StatusText(status),
|
|
75
|
+
Message: message,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
w.Header().Set("Content-Type", "application/json")
|
|
79
|
+
w.WriteHeader(status)
|
|
80
|
+
json.NewEncoder(w).Encode(response)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Support Pagination for Collections
|
|
85
|
+
|
|
86
|
+
**Rule**: Implement pagination for list endpoints.
|
|
87
|
+
|
|
88
|
+
**Good Example**:
|
|
89
|
+
```go
|
|
90
|
+
type PaginationParams struct {
|
|
91
|
+
Page int `json:"page"`
|
|
92
|
+
PageSize int `json:"page_size"`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type PaginatedResponse struct {
|
|
96
|
+
Data interface{} `json:"data"`
|
|
97
|
+
Page int `json:"page"`
|
|
98
|
+
PageSize int `json:"page_size"`
|
|
99
|
+
TotalItems int `json:"total_items"`
|
|
100
|
+
TotalPages int `json:"total_pages"`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
func ListUsers(w http.ResponseWriter, r *http.Request) {
|
|
104
|
+
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
|
105
|
+
if page < 1 {
|
|
106
|
+
page = 1
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
|
|
110
|
+
if pageSize < 1 || pageSize > 100 {
|
|
111
|
+
pageSize = 20
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
users, total, err := db.ListUsers(page, pageSize)
|
|
115
|
+
if err != nil {
|
|
116
|
+
writeError(w, http.StatusInternalServerError, "Failed to list users")
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
response := PaginatedResponse{
|
|
121
|
+
Data: users,
|
|
122
|
+
Page: page,
|
|
123
|
+
PageSize: pageSize,
|
|
124
|
+
TotalItems: total,
|
|
125
|
+
TotalPages: (total + pageSize - 1) / pageSize,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
writeJSON(w, http.StatusOK, response)
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 5. Implement Filtering and Sorting
|
|
133
|
+
|
|
134
|
+
**Rule**: Support filtering and sorting query parameters.
|
|
135
|
+
|
|
136
|
+
**Good Example**:
|
|
137
|
+
```go
|
|
138
|
+
type QueryParams struct {
|
|
139
|
+
Filters map[string]string
|
|
140
|
+
SortBy string
|
|
141
|
+
Order string
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func ParseQueryParams(r *http.Request) *QueryParams {
|
|
145
|
+
params := &QueryParams{
|
|
146
|
+
Filters: make(map[string]string),
|
|
147
|
+
SortBy: r.URL.Query().Get("sort_by"),
|
|
148
|
+
Order: r.URL.Query().Get("order"),
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Parse filter parameters
|
|
152
|
+
for key, values := range r.URL.Query() {
|
|
153
|
+
if strings.HasPrefix(key, "filter_") {
|
|
154
|
+
filterKey := strings.TrimPrefix(key, "filter_")
|
|
155
|
+
params.Filters[filterKey] = values[0]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if params.Order != "asc" && params.Order != "desc" {
|
|
160
|
+
params.Order = "asc"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return params
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
func ListUsersWithFilters(w http.ResponseWriter, r *http.Request) {
|
|
167
|
+
params := ParseQueryParams(r)
|
|
168
|
+
|
|
169
|
+
users, err := db.QueryUsers(params)
|
|
170
|
+
if err != nil {
|
|
171
|
+
writeError(w, http.StatusInternalServerError, "Failed to query users")
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
writeJSON(w, http.StatusOK, users)
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## References
|
|
180
|
+
|
|
181
|
+
- [REST API Design Best Practices](https://restfulapi.net/)
|
|
182
|
+
- [HTTP Status Codes](https://httpstatuses.com/)
|
|
183
|
+
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Cloud Configuration Management Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for managing configuration in cloud-native Go applications including environment variables, config maps, secrets, and external configuration services.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Environment Variables for Configuration
|
|
10
|
+
|
|
11
|
+
**Rule**: Use environment variables for runtime configuration with sensible defaults.
|
|
12
|
+
|
|
13
|
+
**Rationale**: Environment variables are the standard way to configure cloud-native applications across different platforms.
|
|
14
|
+
|
|
15
|
+
**Good Example**:
|
|
16
|
+
```go
|
|
17
|
+
import "github.com/kelseyhightower/envconfig"
|
|
18
|
+
|
|
19
|
+
type Config struct {
|
|
20
|
+
Port int `envconfig:"PORT" default:"8080"`
|
|
21
|
+
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
|
|
22
|
+
LogLevel string `envconfig:"LOG_LEVEL" default:"info"`
|
|
23
|
+
EnableMetrics bool `envconfig:"ENABLE_METRICS" default:"true"`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func LoadConfig() (*Config, error) {
|
|
27
|
+
var cfg Config
|
|
28
|
+
if err := envconfig.Process("", &cfg); err != nil {
|
|
29
|
+
return nil, fmt.Errorf("failed to load config: %w", err)
|
|
30
|
+
}
|
|
31
|
+
return &cfg, nil
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Never Hardcode Secrets
|
|
36
|
+
|
|
37
|
+
**Rule**: Load secrets from environment variables or secret management systems, never hardcode them.
|
|
38
|
+
|
|
39
|
+
**Good Example**:
|
|
40
|
+
```go
|
|
41
|
+
type DatabaseConfig struct {
|
|
42
|
+
Host string `envconfig:"DB_HOST" required:"true"`
|
|
43
|
+
Port int `envconfig:"DB_PORT" default:"5432"`
|
|
44
|
+
User string `envconfig:"DB_USER" required:"true"`
|
|
45
|
+
Password string `envconfig:"DB_PASSWORD" required:"true"` // From secret
|
|
46
|
+
Database string `envconfig:"DB_NAME" required:"true"`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func ConnectDatabase(cfg *DatabaseConfig) (*sql.DB, error) {
|
|
50
|
+
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=require",
|
|
51
|
+
cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database)
|
|
52
|
+
|
|
53
|
+
db, err := sql.Open("postgres", dsn)
|
|
54
|
+
if err != nil {
|
|
55
|
+
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return db, nil
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Support Multiple Configuration Sources
|
|
63
|
+
|
|
64
|
+
**Rule**: Support loading configuration from multiple sources with proper precedence.
|
|
65
|
+
|
|
66
|
+
**Good Example**:
|
|
67
|
+
```go
|
|
68
|
+
import "github.com/spf13/viper"
|
|
69
|
+
|
|
70
|
+
func LoadConfigWithViper() (*Config, error) {
|
|
71
|
+
viper.SetConfigName("config")
|
|
72
|
+
viper.SetConfigType("yaml")
|
|
73
|
+
viper.AddConfigPath("/etc/myapp/")
|
|
74
|
+
viper.AddConfigPath("$HOME/.myapp")
|
|
75
|
+
viper.AddConfigPath(".")
|
|
76
|
+
|
|
77
|
+
// Environment variables take precedence
|
|
78
|
+
viper.AutomaticEnv()
|
|
79
|
+
viper.SetEnvPrefix("MYAPP")
|
|
80
|
+
|
|
81
|
+
if err := viper.ReadInConfig(); err != nil {
|
|
82
|
+
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
|
83
|
+
return nil, fmt.Errorf("failed to read config: %w", err)
|
|
84
|
+
}
|
|
85
|
+
// Config file not found; using env vars and defaults
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var cfg Config
|
|
89
|
+
if err := viper.Unmarshal(&cfg); err != nil {
|
|
90
|
+
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return &cfg, nil
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 4. Validate Configuration on Startup
|
|
98
|
+
|
|
99
|
+
**Rule**: Validate all required configuration values on application startup.
|
|
100
|
+
|
|
101
|
+
**Good Example**:
|
|
102
|
+
```go
|
|
103
|
+
func (c *Config) Validate() error {
|
|
104
|
+
if c.Port < 1 || c.Port > 65535 {
|
|
105
|
+
return fmt.Errorf("invalid port: %d", c.Port)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if c.DatabaseURL == "" {
|
|
109
|
+
return fmt.Errorf("DATABASE_URL is required")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
validLogLevels := map[string]bool{
|
|
113
|
+
"debug": true, "info": true, "warn": true, "error": true,
|
|
114
|
+
}
|
|
115
|
+
if !validLogLevels[c.LogLevel] {
|
|
116
|
+
return fmt.Errorf("invalid log level: %s", c.LogLevel)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return nil
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func main() {
|
|
123
|
+
cfg, err := LoadConfig()
|
|
124
|
+
if err != nil {
|
|
125
|
+
log.Fatalf("Failed to load config: %v", err)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if err := cfg.Validate(); err != nil {
|
|
129
|
+
log.Fatalf("Invalid configuration: %v", err)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Start application
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 5. Support Hot Reloading for Non-Critical Config
|
|
137
|
+
|
|
138
|
+
**Rule**: Implement hot reloading for configuration that can be changed without restart.
|
|
139
|
+
|
|
140
|
+
**Good Example**:
|
|
141
|
+
```go
|
|
142
|
+
type ConfigManager struct {
|
|
143
|
+
mu sync.RWMutex
|
|
144
|
+
config *Config
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func (cm *ConfigManager) Get() *Config {
|
|
148
|
+
cm.mu.RLock()
|
|
149
|
+
defer cm.mu.RUnlock()
|
|
150
|
+
return cm.config
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func (cm *ConfigManager) Reload() error {
|
|
154
|
+
newConfig, err := LoadConfig()
|
|
155
|
+
if err != nil {
|
|
156
|
+
return fmt.Errorf("failed to reload config: %w", err)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if err := newConfig.Validate(); err != nil {
|
|
160
|
+
return fmt.Errorf("invalid config: %w", err)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
cm.mu.Lock()
|
|
164
|
+
cm.config = newConfig
|
|
165
|
+
cm.mu.Unlock()
|
|
166
|
+
|
|
167
|
+
log.Println("Configuration reloaded successfully")
|
|
168
|
+
return nil
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func (cm *ConfigManager) WatchForChanges(ctx context.Context) {
|
|
172
|
+
ticker := time.NewTicker(30 * time.Second)
|
|
173
|
+
defer ticker.Stop()
|
|
174
|
+
|
|
175
|
+
for {
|
|
176
|
+
select {
|
|
177
|
+
case <-ctx.Done():
|
|
178
|
+
return
|
|
179
|
+
case <-ticker.C:
|
|
180
|
+
if err := cm.Reload(); err != nil {
|
|
181
|
+
log.Printf("Failed to reload config: %v", err)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## References
|
|
189
|
+
|
|
190
|
+
- [The Twelve-Factor App - Config](https://12factor.net/config)
|
|
191
|
+
- [Viper Configuration Library](https://github.com/spf13/viper)
|
|
192
|
+
- [Envconfig](https://github.com/kelseyhightower/envconfig)
|
|
193
|
+
|