@ngxtm/devkit 3.4.0 → 3.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/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
- package/skills/learn/SKILL.md +476 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Validator Validation Tags
|
|
2
|
+
|
|
3
|
+
## Basic Usage
|
|
4
|
+
|
|
5
|
+
```go
|
|
6
|
+
import (
|
|
7
|
+
"github.com/go-playground/validator/v10"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type User struct {
|
|
11
|
+
Name string `validate:"required,min=2,max=100"`
|
|
12
|
+
Email string `validate:"required,email"`
|
|
13
|
+
Age int `validate:"gte=0,lte=130"`
|
|
14
|
+
Password string `validate:"required,min=8"`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func main() {
|
|
18
|
+
validate := validator.New()
|
|
19
|
+
|
|
20
|
+
user := User{
|
|
21
|
+
Name: "J",
|
|
22
|
+
Email: "invalid",
|
|
23
|
+
Age: -1,
|
|
24
|
+
Password: "short",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
err := validate.Struct(user)
|
|
28
|
+
if err != nil {
|
|
29
|
+
for _, err := range err.(validator.ValidationErrors) {
|
|
30
|
+
fmt.Printf("Field: %s, Tag: %s, Value: %v\n",
|
|
31
|
+
err.Field(), err.Tag(), err.Value())
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Common Tags
|
|
38
|
+
|
|
39
|
+
```go
|
|
40
|
+
type Example struct {
|
|
41
|
+
// Required fields
|
|
42
|
+
Required string `validate:"required"`
|
|
43
|
+
RequiredIf string `validate:"required_if=Type email"`
|
|
44
|
+
RequiredWith string `validate:"required_with=Other"`
|
|
45
|
+
|
|
46
|
+
// String length
|
|
47
|
+
MinLen string `validate:"min=3"`
|
|
48
|
+
MaxLen string `validate:"max=100"`
|
|
49
|
+
Len string `validate:"len=10"`
|
|
50
|
+
|
|
51
|
+
// Numeric ranges
|
|
52
|
+
Gt int `validate:"gt=0"`
|
|
53
|
+
Gte int `validate:"gte=1"`
|
|
54
|
+
Lt int `validate:"lt=100"`
|
|
55
|
+
Lte int `validate:"lte=99"`
|
|
56
|
+
|
|
57
|
+
// Format validators
|
|
58
|
+
Email string `validate:"email"`
|
|
59
|
+
URL string `validate:"url"`
|
|
60
|
+
UUID string `validate:"uuid"`
|
|
61
|
+
IP string `validate:"ip"`
|
|
62
|
+
IPv4 string `validate:"ipv4"`
|
|
63
|
+
|
|
64
|
+
// Comparisons
|
|
65
|
+
Eq string `validate:"eq=admin"`
|
|
66
|
+
Ne string `validate:"ne=guest"`
|
|
67
|
+
OneOf string `validate:"oneof=red green blue"`
|
|
68
|
+
|
|
69
|
+
// Content
|
|
70
|
+
Alpha string `validate:"alpha"`
|
|
71
|
+
Alphanum string `validate:"alphanum"`
|
|
72
|
+
Numeric string `validate:"numeric"`
|
|
73
|
+
Contains string `validate:"contains=@"`
|
|
74
|
+
StartsWith string `validate:"startswith=prefix_"`
|
|
75
|
+
EndsWith string `validate:"endswith=_suffix"`
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Nested Validation
|
|
80
|
+
|
|
81
|
+
```go
|
|
82
|
+
type Address struct {
|
|
83
|
+
Street string `validate:"required"`
|
|
84
|
+
City string `validate:"required"`
|
|
85
|
+
ZipCode string `validate:"required,numeric,len=5"`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type User struct {
|
|
89
|
+
Name string `validate:"required"`
|
|
90
|
+
Address Address `validate:"required"` // Validates nested struct
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Slice validation with dive
|
|
94
|
+
type Order struct {
|
|
95
|
+
Items []OrderItem `validate:"required,dive"` // Validates each item
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type OrderItem struct {
|
|
99
|
+
ProductID string `validate:"required,uuid"`
|
|
100
|
+
Quantity int `validate:"required,gt=0"`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Map validation
|
|
104
|
+
type Config struct {
|
|
105
|
+
Settings map[string]string `validate:"dive,keys,required,endkeys,required"`
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Custom Validators
|
|
110
|
+
|
|
111
|
+
```go
|
|
112
|
+
func main() {
|
|
113
|
+
validate := validator.New()
|
|
114
|
+
|
|
115
|
+
// Custom validation function
|
|
116
|
+
validate.RegisterValidation("strongpassword", func(fl validator.FieldLevel) bool {
|
|
117
|
+
password := fl.Field().String()
|
|
118
|
+
hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password)
|
|
119
|
+
hasLower := regexp.MustCompile(`[a-z]`).MatchString(password)
|
|
120
|
+
hasNumber := regexp.MustCompile(`[0-9]`).MatchString(password)
|
|
121
|
+
return len(password) >= 8 && hasUpper && hasLower && hasNumber
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
type User struct {
|
|
125
|
+
Password string `validate:"required,strongpassword"`
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Conditional Validation
|
|
131
|
+
|
|
132
|
+
```go
|
|
133
|
+
type Payment struct {
|
|
134
|
+
Type string `validate:"required,oneof=card bank crypto"`
|
|
135
|
+
CardNumber string `validate:"required_if=Type card,omitempty,credit_card"`
|
|
136
|
+
BankAccount string `validate:"required_if=Type bank,omitempty"`
|
|
137
|
+
WalletAddress string `validate:"required_if=Type crypto,omitempty"`
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type User struct {
|
|
141
|
+
Type string `validate:"required,oneof=individual company"`
|
|
142
|
+
// Required only if Type is "company"
|
|
143
|
+
CompanyName string `validate:"required_if=Type company"`
|
|
144
|
+
TaxID string `validate:"required_if=Type company"`
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Error Handling
|
|
149
|
+
|
|
150
|
+
```go
|
|
151
|
+
func validateAndRespond(w http.ResponseWriter, data interface{}) error {
|
|
152
|
+
if err := validate.Struct(data); err != nil {
|
|
153
|
+
var errors []string
|
|
154
|
+
|
|
155
|
+
for _, err := range err.(validator.ValidationErrors) {
|
|
156
|
+
field := err.Field()
|
|
157
|
+
tag := err.Tag()
|
|
158
|
+
param := err.Param()
|
|
159
|
+
|
|
160
|
+
var message string
|
|
161
|
+
switch tag {
|
|
162
|
+
case "required":
|
|
163
|
+
message = fmt.Sprintf("%s is required", field)
|
|
164
|
+
case "email":
|
|
165
|
+
message = fmt.Sprintf("%s must be a valid email", field)
|
|
166
|
+
case "min":
|
|
167
|
+
message = fmt.Sprintf("%s must be at least %s characters", field, param)
|
|
168
|
+
case "max":
|
|
169
|
+
message = fmt.Sprintf("%s must be at most %s characters", field, param)
|
|
170
|
+
default:
|
|
171
|
+
message = fmt.Sprintf("%s failed validation: %s", field, tag)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
errors = append(errors, message)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return fmt.Errorf("validation failed: %v", errors)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return nil
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Integration with Gin/Echo
|
|
185
|
+
|
|
186
|
+
```go
|
|
187
|
+
// Gin
|
|
188
|
+
type CreateUserRequest struct {
|
|
189
|
+
Name string `json:"name" binding:"required,min=2"`
|
|
190
|
+
Email string `json:"email" binding:"required,email"`
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func createUser(c *gin.Context) {
|
|
194
|
+
var req CreateUserRequest
|
|
195
|
+
if err := c.ShouldBindJSON(&req); err != nil {
|
|
196
|
+
c.JSON(400, gin.H{"error": err.Error()})
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Echo (custom validator)
|
|
202
|
+
type CustomValidator struct {
|
|
203
|
+
validator *validator.Validate
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
func (cv *CustomValidator) Validate(i interface{}) error {
|
|
207
|
+
return cv.validator.Struct(i)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
e.Validator = &CustomValidator{validator: validator.New()}
|
|
211
|
+
```
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Viper Config
|
|
3
|
+
description: Complete configuration solution for Go applications.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [golang, viper, config, configuration]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/config.go', 'config.yaml', 'config.json']
|
|
8
|
+
keywords: [viper, GetString, SetDefault, ReadInConfig]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Viper Config Standards
|
|
12
|
+
|
|
13
|
+
## Basic Setup
|
|
14
|
+
|
|
15
|
+
```go
|
|
16
|
+
import "github.com/spf13/viper"
|
|
17
|
+
|
|
18
|
+
func initConfig() {
|
|
19
|
+
viper.SetConfigName("config") // config file name (no extension)
|
|
20
|
+
viper.SetConfigType("yaml") // config file type
|
|
21
|
+
viper.AddConfigPath(".") // look in current dir
|
|
22
|
+
viper.AddConfigPath("$HOME/.app") // look in home dir
|
|
23
|
+
viper.AddConfigPath("/etc/app/") // look in /etc
|
|
24
|
+
|
|
25
|
+
if err := viper.ReadInConfig(); err != nil {
|
|
26
|
+
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
|
27
|
+
// Config file not found, use defaults
|
|
28
|
+
} else {
|
|
29
|
+
log.Fatalf("Error reading config: %v", err)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Configuration File
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
# config.yaml
|
|
39
|
+
server:
|
|
40
|
+
host: localhost
|
|
41
|
+
port: 8080
|
|
42
|
+
timeout: 30s
|
|
43
|
+
|
|
44
|
+
database:
|
|
45
|
+
url: postgres://user:pass@localhost/db
|
|
46
|
+
max_connections: 100
|
|
47
|
+
|
|
48
|
+
features:
|
|
49
|
+
cache_enabled: true
|
|
50
|
+
debug_mode: false
|
|
51
|
+
|
|
52
|
+
allowed_origins:
|
|
53
|
+
- http://localhost:3000
|
|
54
|
+
- https://example.com
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Reading Values
|
|
58
|
+
|
|
59
|
+
```go
|
|
60
|
+
// Strings
|
|
61
|
+
host := viper.GetString("server.host")
|
|
62
|
+
|
|
63
|
+
// Integers
|
|
64
|
+
port := viper.GetInt("server.port")
|
|
65
|
+
|
|
66
|
+
// Booleans
|
|
67
|
+
debug := viper.GetBool("features.debug_mode")
|
|
68
|
+
|
|
69
|
+
// Duration
|
|
70
|
+
timeout := viper.GetDuration("server.timeout")
|
|
71
|
+
|
|
72
|
+
// Slices
|
|
73
|
+
origins := viper.GetStringSlice("allowed_origins")
|
|
74
|
+
|
|
75
|
+
// Maps
|
|
76
|
+
settings := viper.GetStringMapString("settings")
|
|
77
|
+
|
|
78
|
+
// Check if key exists
|
|
79
|
+
if viper.IsSet("database.url") {
|
|
80
|
+
// ...
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Defaults
|
|
85
|
+
|
|
86
|
+
```go
|
|
87
|
+
func setDefaults() {
|
|
88
|
+
viper.SetDefault("server.host", "localhost")
|
|
89
|
+
viper.SetDefault("server.port", 8080)
|
|
90
|
+
viper.SetDefault("database.max_connections", 10)
|
|
91
|
+
viper.SetDefault("features.cache_enabled", true)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Environment Variables
|
|
96
|
+
|
|
97
|
+
```go
|
|
98
|
+
func initConfig() {
|
|
99
|
+
// Automatically read env vars
|
|
100
|
+
viper.AutomaticEnv()
|
|
101
|
+
|
|
102
|
+
// Replace . with _ in env var names
|
|
103
|
+
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
104
|
+
|
|
105
|
+
// Prefix for env vars: APP_SERVER_PORT
|
|
106
|
+
viper.SetEnvPrefix("APP")
|
|
107
|
+
|
|
108
|
+
// Bind specific env var
|
|
109
|
+
viper.BindEnv("database.url", "DATABASE_URL")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Environment: APP_SERVER_PORT=9000
|
|
113
|
+
// viper.GetInt("server.port") returns 9000
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Unmarshal to Struct
|
|
117
|
+
|
|
118
|
+
```go
|
|
119
|
+
type Config struct {
|
|
120
|
+
Server ServerConfig `mapstructure:"server"`
|
|
121
|
+
Database DatabaseConfig `mapstructure:"database"`
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type ServerConfig struct {
|
|
125
|
+
Host string `mapstructure:"host"`
|
|
126
|
+
Port int `mapstructure:"port"`
|
|
127
|
+
Timeout time.Duration `mapstructure:"timeout"`
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
type DatabaseConfig struct {
|
|
131
|
+
URL string `mapstructure:"url"`
|
|
132
|
+
MaxConnections int `mapstructure:"max_connections"`
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
func LoadConfig() (*Config, error) {
|
|
136
|
+
var cfg Config
|
|
137
|
+
if err := viper.Unmarshal(&cfg); err != nil {
|
|
138
|
+
return nil, err
|
|
139
|
+
}
|
|
140
|
+
return &cfg, nil
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Sub-config
|
|
144
|
+
func LoadServerConfig() (*ServerConfig, error) {
|
|
145
|
+
var cfg ServerConfig
|
|
146
|
+
if err := viper.UnmarshalKey("server", &cfg); err != nil {
|
|
147
|
+
return nil, err
|
|
148
|
+
}
|
|
149
|
+
return &cfg, nil
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Live Watching
|
|
154
|
+
|
|
155
|
+
```go
|
|
156
|
+
import "github.com/fsnotify/fsnotify"
|
|
157
|
+
|
|
158
|
+
func initConfig() {
|
|
159
|
+
viper.WatchConfig()
|
|
160
|
+
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
161
|
+
fmt.Println("Config changed:", e.Name)
|
|
162
|
+
// Reload application config
|
|
163
|
+
reloadConfig()
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Cobra Integration
|
|
169
|
+
|
|
170
|
+
```go
|
|
171
|
+
import (
|
|
172
|
+
"github.com/spf13/cobra"
|
|
173
|
+
"github.com/spf13/viper"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
var cfgFile string
|
|
177
|
+
|
|
178
|
+
var rootCmd = &cobra.Command{
|
|
179
|
+
Use: "app",
|
|
180
|
+
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
|
181
|
+
return initConfig()
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
func init() {
|
|
186
|
+
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
|
|
187
|
+
rootCmd.PersistentFlags().Int("port", 8080, "server port")
|
|
188
|
+
|
|
189
|
+
// Bind flag to viper
|
|
190
|
+
viper.BindPFlag("server.port", rootCmd.PersistentFlags().Lookup("port"))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func initConfig() error {
|
|
194
|
+
if cfgFile != "" {
|
|
195
|
+
viper.SetConfigFile(cfgFile)
|
|
196
|
+
} else {
|
|
197
|
+
viper.SetConfigName("config")
|
|
198
|
+
viper.AddConfigPath(".")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
viper.AutomaticEnv()
|
|
202
|
+
return viper.ReadInConfig()
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Multiple Config Files
|
|
207
|
+
|
|
208
|
+
```go
|
|
209
|
+
// Merge multiple configs
|
|
210
|
+
viper.SetConfigName("config")
|
|
211
|
+
viper.ReadInConfig()
|
|
212
|
+
|
|
213
|
+
viper.SetConfigName("config.local")
|
|
214
|
+
viper.MergeInConfig() // Merge with existing
|
|
215
|
+
|
|
216
|
+
// Or read specific file
|
|
217
|
+
viper.SetConfigFile("/path/to/config.yaml")
|
|
218
|
+
viper.MergeInConfig()
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Writing Config
|
|
222
|
+
|
|
223
|
+
```go
|
|
224
|
+
// Write current config
|
|
225
|
+
viper.WriteConfig()
|
|
226
|
+
|
|
227
|
+
// Write to specific file
|
|
228
|
+
viper.WriteConfigAs("./config.new.yaml")
|
|
229
|
+
|
|
230
|
+
// Safe write (don't overwrite)
|
|
231
|
+
viper.SafeWriteConfig()
|
|
232
|
+
|
|
233
|
+
// Set values programmatically
|
|
234
|
+
viper.Set("server.port", 9000)
|
|
235
|
+
viper.WriteConfig()
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Best Practices
|
|
239
|
+
|
|
240
|
+
1. **Defaults**: Always set sensible defaults
|
|
241
|
+
2. **Environment**: Use `AutomaticEnv()` for 12-factor apps
|
|
242
|
+
3. **Struct binding**: Unmarshal to typed config structs
|
|
243
|
+
4. **Validation**: Validate config after loading
|
|
244
|
+
5. **Secrets**: Use env vars for secrets, not config files
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Viper Configuration References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Config Loading**](config-loading.md) - Files, env vars, defaults
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Set sensible defaults
|
|
10
|
+
- [ ] Support multiple config formats
|
|
11
|
+
- [ ] Environment variable overrides
|
|
12
|
+
- [ ] AutomaticEnv for env var binding
|
|
13
|
+
- [ ] Watch for config changes
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Viper Config Loading
|
|
2
|
+
|
|
3
|
+
## Basic Usage
|
|
4
|
+
|
|
5
|
+
```go
|
|
6
|
+
import "github.com/spf13/viper"
|
|
7
|
+
|
|
8
|
+
func LoadConfig() error {
|
|
9
|
+
// Config file name (without extension)
|
|
10
|
+
viper.SetConfigName("config")
|
|
11
|
+
|
|
12
|
+
// Config file type
|
|
13
|
+
viper.SetConfigType("yaml")
|
|
14
|
+
|
|
15
|
+
// Search paths
|
|
16
|
+
viper.AddConfigPath(".")
|
|
17
|
+
viper.AddConfigPath("./config")
|
|
18
|
+
viper.AddConfigPath("$HOME/.myapp")
|
|
19
|
+
|
|
20
|
+
// Read config
|
|
21
|
+
if err := viper.ReadInConfig(); err != nil {
|
|
22
|
+
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
|
23
|
+
// Config file not found, use defaults
|
|
24
|
+
} else {
|
|
25
|
+
return err
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return nil
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Access values
|
|
33
|
+
func main() {
|
|
34
|
+
LoadConfig()
|
|
35
|
+
|
|
36
|
+
host := viper.GetString("server.host")
|
|
37
|
+
port := viper.GetInt("server.port")
|
|
38
|
+
debug := viper.GetBool("debug")
|
|
39
|
+
timeout := viper.GetDuration("timeout")
|
|
40
|
+
hosts := viper.GetStringSlice("allowed_hosts")
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Defaults
|
|
45
|
+
|
|
46
|
+
```go
|
|
47
|
+
func SetDefaults() {
|
|
48
|
+
viper.SetDefault("server.host", "localhost")
|
|
49
|
+
viper.SetDefault("server.port", 8080)
|
|
50
|
+
viper.SetDefault("database.driver", "postgres")
|
|
51
|
+
viper.SetDefault("log.level", "info")
|
|
52
|
+
viper.SetDefault("timeout", "30s")
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Environment Variables
|
|
57
|
+
|
|
58
|
+
```go
|
|
59
|
+
func LoadConfig() {
|
|
60
|
+
// Prefix for env vars (e.g., MYAPP_SERVER_PORT)
|
|
61
|
+
viper.SetEnvPrefix("MYAPP")
|
|
62
|
+
|
|
63
|
+
// Replace dots with underscores in env var names
|
|
64
|
+
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
65
|
+
|
|
66
|
+
// Automatically bind all keys to env vars
|
|
67
|
+
viper.AutomaticEnv()
|
|
68
|
+
|
|
69
|
+
// Or bind specific keys
|
|
70
|
+
viper.BindEnv("server.port", "PORT") // Binds PORT env var
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Example: MYAPP_SERVER_PORT=9000 overrides server.port
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Unmarshal to Struct
|
|
77
|
+
|
|
78
|
+
```go
|
|
79
|
+
type Config struct {
|
|
80
|
+
Server ServerConfig `mapstructure:"server"`
|
|
81
|
+
Database DatabaseConfig `mapstructure:"database"`
|
|
82
|
+
Log LogConfig `mapstructure:"log"`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type ServerConfig struct {
|
|
86
|
+
Host string `mapstructure:"host"`
|
|
87
|
+
Port int `mapstructure:"port"`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type DatabaseConfig struct {
|
|
91
|
+
Driver string `mapstructure:"driver"`
|
|
92
|
+
Host string `mapstructure:"host"`
|
|
93
|
+
Port int `mapstructure:"port"`
|
|
94
|
+
Name string `mapstructure:"name"`
|
|
95
|
+
User string `mapstructure:"user"`
|
|
96
|
+
Password string `mapstructure:"password"`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
type LogConfig struct {
|
|
100
|
+
Level string `mapstructure:"level"`
|
|
101
|
+
Format string `mapstructure:"format"`
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func LoadConfig() (*Config, error) {
|
|
105
|
+
viper.SetConfigName("config")
|
|
106
|
+
viper.AddConfigPath(".")
|
|
107
|
+
|
|
108
|
+
if err := viper.ReadInConfig(); err != nil {
|
|
109
|
+
return nil, err
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var config Config
|
|
113
|
+
if err := viper.Unmarshal(&config); err != nil {
|
|
114
|
+
return nil, err
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return &config, nil
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Watch for Changes
|
|
122
|
+
|
|
123
|
+
```go
|
|
124
|
+
func WatchConfig(onChange func()) {
|
|
125
|
+
viper.WatchConfig()
|
|
126
|
+
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
127
|
+
log.Println("Config file changed:", e.Name)
|
|
128
|
+
onChange()
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Multiple Config Files
|
|
134
|
+
|
|
135
|
+
```go
|
|
136
|
+
func LoadConfigs() error {
|
|
137
|
+
// Main config
|
|
138
|
+
viper.SetConfigName("config")
|
|
139
|
+
viper.AddConfigPath(".")
|
|
140
|
+
if err := viper.ReadInConfig(); err != nil {
|
|
141
|
+
return err
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Merge additional config
|
|
145
|
+
viper.SetConfigName("secrets")
|
|
146
|
+
if err := viper.MergeInConfig(); err != nil {
|
|
147
|
+
// Secrets file optional
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return nil
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Example Config File
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
# config.yaml
|
|
158
|
+
server:
|
|
159
|
+
host: localhost
|
|
160
|
+
port: 8080
|
|
161
|
+
|
|
162
|
+
database:
|
|
163
|
+
driver: postgres
|
|
164
|
+
host: localhost
|
|
165
|
+
port: 5432
|
|
166
|
+
name: myapp
|
|
167
|
+
user: postgres
|
|
168
|
+
password: ${DB_PASSWORD} # Use env var
|
|
169
|
+
|
|
170
|
+
log:
|
|
171
|
+
level: info
|
|
172
|
+
format: json
|
|
173
|
+
|
|
174
|
+
features:
|
|
175
|
+
enable_cache: true
|
|
176
|
+
cache_ttl: 5m
|
|
177
|
+
|
|
178
|
+
allowed_origins:
|
|
179
|
+
- http://localhost:3000
|
|
180
|
+
- https://example.com
|
|
181
|
+
```
|