Skip to content

Commit 95c3288

Browse files
Quickstart example app (#31)
* add quickstart example apps * quote-of-the-day * add nil check
1 parent aff0698 commit 95c3288

13 files changed

Lines changed: 1091 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
8+
"github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration"
9+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
10+
)
11+
12+
func loadAzureAppConfiguration(ctx context.Context) (*azureappconfiguration.AzureAppConfiguration, error) {
13+
// Get the endpoint from environment variable
14+
endpoint := os.Getenv("AZURE_APPCONFIG_ENDPOINT")
15+
if endpoint == "" {
16+
log.Fatal("AZURE_APPCONFIG_ENDPOINT environment variable is not set")
17+
}
18+
19+
// Create a credential using DefaultAzureCredential
20+
credential, err := azidentity.NewDefaultAzureCredential(nil)
21+
if err != nil {
22+
log.Fatalf("Failed to create credential: %v", err)
23+
}
24+
25+
// Set up authentication options with endpoint and credential
26+
authOptions := azureappconfiguration.AuthenticationOptions{
27+
Endpoint: endpoint,
28+
Credential: credential,
29+
}
30+
31+
// Configure feature flag options
32+
options := &azureappconfiguration.Options{
33+
FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{
34+
Enabled: true,
35+
RefreshOptions: azureappconfiguration.RefreshOptions{
36+
Enabled: true,
37+
},
38+
},
39+
}
40+
41+
// Load configuration from Azure App Configuration
42+
appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)
43+
if err != nil {
44+
log.Fatalf("Failed to load configuration: %v", err)
45+
}
46+
47+
return appConfig, nil
48+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"net/http"
8+
9+
"github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration"
10+
"github.com/gin-gonic/gin"
11+
"github.com/microsoft/Featuremanagement-Go/featuremanagement"
12+
"github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig"
13+
)
14+
15+
type WebApp struct {
16+
featureManager *featuremanagement.FeatureManager
17+
appConfig *azureappconfiguration.AzureAppConfiguration
18+
}
19+
20+
func (app *WebApp) refreshMiddleware() gin.HandlerFunc {
21+
return func(c *gin.Context) {
22+
go func() {
23+
ctx := context.Background()
24+
if err := app.appConfig.Refresh(ctx); err != nil {
25+
log.Printf("Error refreshing configuration: %v", err)
26+
}
27+
}()
28+
c.Next()
29+
}
30+
}
31+
32+
func (app *WebApp) featureMiddleware() gin.HandlerFunc {
33+
return func(c *gin.Context) {
34+
// Check if Beta feature is enabled
35+
betaEnabled, err := app.featureManager.IsEnabled("Beta")
36+
if err != nil {
37+
log.Printf("Error checking Beta feature: %v", err)
38+
betaEnabled = false
39+
}
40+
41+
// Store feature flag status for use in templates
42+
c.Set("betaEnabled", betaEnabled)
43+
c.Next()
44+
}
45+
}
46+
47+
func (app *WebApp) setupRoutes(r *gin.Engine) {
48+
r.Use(app.refreshMiddleware())
49+
r.Use(app.featureMiddleware())
50+
51+
// Load HTML templates
52+
r.LoadHTMLGlob("templates/*.html")
53+
54+
// Routes
55+
r.GET("/", app.homeHandler)
56+
r.GET("/beta", app.betaHandler)
57+
}
58+
59+
// Home page handler
60+
func (app *WebApp) homeHandler(c *gin.Context) {
61+
betaEnabled := c.GetBool("betaEnabled")
62+
63+
c.HTML(http.StatusOK, "index.html", gin.H{
64+
"title": "Feature Management Example App",
65+
"betaEnabled": betaEnabled,
66+
})
67+
}
68+
69+
// Beta page handler
70+
func (app *WebApp) betaHandler(c *gin.Context) {
71+
betaEnabled := c.GetBool("betaEnabled")
72+
73+
if !betaEnabled {
74+
return
75+
}
76+
77+
c.HTML(http.StatusOK, "beta.html", gin.H{
78+
"title": "Beta Page",
79+
})
80+
}
81+
82+
func main() {
83+
ctx := context.Background()
84+
85+
// Load Azure App Configuration
86+
appConfig, err := loadAzureAppConfiguration(ctx)
87+
if err != nil {
88+
log.Fatalf("Error loading Azure App Configuration: %v", err)
89+
}
90+
91+
// Create feature flag provider
92+
featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig)
93+
if err != nil {
94+
log.Fatalf("Error creating feature flag provider: %v", err)
95+
}
96+
97+
// Create feature manager
98+
featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil)
99+
if err != nil {
100+
log.Fatalf("Error creating feature manager: %v", err)
101+
}
102+
103+
// Create web app
104+
app := &WebApp{
105+
featureManager: featureManager,
106+
appConfig: appConfig,
107+
}
108+
109+
// Set up Gin with default middleware (Logger and Recovery)
110+
r := gin.Default()
111+
112+
// Set up routes
113+
app.setupRoutes(r)
114+
115+
// Start server
116+
fmt.Println("Starting server on http://localhost:8080")
117+
fmt.Println("Open http://localhost:8080 in your browser")
118+
fmt.Println("Toggle the 'Beta' feature flag in Azure portal to see changes")
119+
fmt.Println()
120+
121+
if err := r.Run(":8080"); err != nil {
122+
log.Fatalf("Failed to start server: %v", err)
123+
}
124+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>{{.title}}</title>
7+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8+
</head>
9+
<body>
10+
<!-- Navigation --> <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
11+
<div class="container">
12+
<a class="navbar-brand" href="/">TestAppConfig</a>
13+
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
14+
<ul class="navbar-nav flex-grow-1">
15+
<li class="nav-item">
16+
<a class="nav-link text-dark" href="/">Home</a>
17+
</li>
18+
<li class="nav-item">
19+
<a class="nav-link text-dark" href="/beta">Beta</a>
20+
</li>
21+
</ul>
22+
</div>
23+
</div>
24+
</nav> <div class="container">
25+
<div class="row justify-content-center">
26+
<div class="col-md-8 text-center">
27+
<h1>This is the beta website.</h1>
28+
</div>
29+
</div>
30+
</div>
31+
32+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
33+
</body>
34+
</html>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>{{.title}}</title>
7+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8+
</head>
9+
<body>
10+
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
11+
<div class="container">
12+
<a class="navbar-brand" href="/">TestAppConfig</a>
13+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
14+
aria-expanded="false" aria-label="Toggle navigation">
15+
<span class="navbar-toggler-icon"></span>
16+
</button>
17+
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
18+
<ul class="navbar-nav flex-grow-1">
19+
<li class="nav-item">
20+
<a class="nav-link text-dark" href="/">Home</a>
21+
</li>
22+
{{if .betaEnabled}}
23+
<li class="nav-item">
24+
<a class="nav-link text-dark" href="/beta">Beta</a>
25+
</li>
26+
{{end}}
27+
</ul>
28+
</div>
29+
</div>
30+
</nav> <div class="container">
31+
<div class="row justify-content-center">
32+
<div class="col-md-8 text-center">
33+
<h1>Hello from Azure App Configuration</h1>
34+
</div>
35+
</div>
36+
37+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
38+
</body>
39+
</html>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
8+
"github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration"
9+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
10+
)
11+
12+
func loadAzureAppConfiguration(ctx context.Context) (*azureappconfiguration.AzureAppConfiguration, error) {
13+
// Get the endpoint from environment variable
14+
endpoint := os.Getenv("AZURE_APPCONFIG_ENDPOINT")
15+
if endpoint == "" {
16+
log.Fatal("AZURE_APPCONFIG_ENDPOINT environment variable is not set")
17+
}
18+
19+
// Create a credential using DefaultAzureCredential
20+
credential, err := azidentity.NewDefaultAzureCredential(nil)
21+
if err != nil {
22+
log.Fatalf("Failed to create credential: %v", err)
23+
}
24+
25+
// Set up authentication options with endpoint and credential
26+
authOptions := azureappconfiguration.AuthenticationOptions{
27+
Endpoint: endpoint,
28+
Credential: credential,
29+
}
30+
31+
// Set up options to enable feature flags
32+
options := &azureappconfiguration.Options{
33+
FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{
34+
Enabled: true,
35+
RefreshOptions: azureappconfiguration.RefreshOptions{
36+
Enabled: true,
37+
},
38+
},
39+
}
40+
41+
// Load configuration from Azure App Configuration
42+
appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)
43+
if err != nil {
44+
log.Fatalf("Failed to load configuration: %v", err)
45+
}
46+
47+
return appConfig, nil
48+
}

0 commit comments

Comments
 (0)