Skip to content

Commit a3a9140

Browse files
authored
Merge pull request #3137 from matzefriedrich/parsley-recipe-v1-update
Updates the example for a Parsley-enabled app
2 parents 6cad36e + ca32a8f commit a3a9140

File tree

8 files changed

+222
-41
lines changed

8 files changed

+222
-41
lines changed

parsley/README.md

Lines changed: 200 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,215 @@ description: Using Parsley for dependency injection in an application.
1010

1111
This example demonstrates integrating the [Parsley dependency injection framework](https://github.com/matzefriedrich/parsley) into a GoFiber web application. The goal is to showcase how dependency injection can create a clean, maintainable, and modular structure in your GoFiber projects.
1212

13+
14+
## Prerequisites
15+
16+
* Go 1.23+
17+
18+
1319
## Overview
1420

15-
In this example, we use Parsley to:
21+
In this example, we use [Parsley](https://github.com/matzefriedrich/parsley) to:
22+
23+
* **Bootstrap the application:** Set up and configure the Fiber app using Parsley’s DI container.
24+
* **Register dependencies:** Define and register services and route handlers with the DI container.
25+
* **Resolve dependencies:** Automatically resolve and inject them where needed.
1626

17-
* **Bootstrap the Application:** Set up and configure the Fiber app using Parsley’s DI container.
18-
* **Register Dependencies:** Define and register services and route handlers with the DI container.
19-
* **Resolve Dependencies:** Automatically resolve and inject them where needed.
2027

21-
## Key Features
28+
### Key features
2229

23-
* **Modular Configuration:** Services are registered in modules, allowing for a clean separation of concerns.
24-
* **Automatic Dependency Injection:** Constructor-based dependency injection wire services together.
25-
* **Simplified Route Management:** Route handlers are registered and managed via the DI container, making it easy to extend and maintain.
30+
* **Modular configuration:** Services are registered in modules, allowing for a clean separation of concerns.
31+
* **Automatic dependency injection:** Constructor-based dependency injection wires services together.
32+
* **Simplified route management:** Route handlers are registered and managed via the DI container, making it easy to extend and maintain.
2633

27-
## How It Works
34+
35+
## How it works
2836

2937
* The `main` function bootstraps the application using Parsley’s `RunParsleyApplication` function.
3038
* Modules define how services (such as the Fiber app and route handlers) are registered and configured.
31-
* Route handlers are implemented as services that receive their dependencies (like the `Greeter` service) via constructor injection.
32-
The `Greeter` service is a simple example of how services can be injected and used within route handlers to handle HTTP requests.
39+
* Route handlers are implemented as services that receive their dependencies (like the `Greeter` service) via constructor injection. The `Greeter` service is a simple example of how services can be injected and used within route handlers to handle requests.
40+
41+
42+
## The recipe - step by step
43+
44+
This guide demonstrates integrating the Parsley dependency injection framework with the GoFiber web framework. You can either clone the GoFiber recipes repository and navigate to the **parsley** example, or replicate each module while following the article:
45+
46+
```sh
47+
git clone https://github.com/gofiber/recipes.git
48+
cd recipes/parsley
49+
```
50+
51+
The main entry point of the application is in the `cmd/main.go`.
52+
53+
```go
54+
package main
55+
56+
import (
57+
"context"
58+
59+
"github.com/gofiber/recipes/parsley-app/internal"
60+
"github.com/gofiber/recipes/parsley-app/internal/modules"
61+
62+
"github.com/matzefriedrich/parsley/pkg/bootstrap"
63+
)
64+
65+
func main() {
66+
67+
ctx := context.Background()
68+
69+
// Runs a Fiber instance as a Parsley-enabled app
70+
bootstrap.RunParsleyApplication(ctx, internal.NewApp,
71+
modules.ConfigureFiber,
72+
modules.ConfigureGreeter)
73+
}
74+
```
75+
76+
In this file, the `RunParsleyApplication` function bootstraps the application. It initializes the Parsley application context and configures the GoFiber server with the necessary services and route handlers. Parsley's `bootstrap` package is generic and could also be used with other web application frameworks; the glue is the `NewApp` method, representing a constructor function that must return a `bootstrap.Application` instance.
77+
78+
The last parameter of the `RunParsleyApplication` function is an ellipsis parameter accepting `ModuleFunc` values representing service registration functions, which are invoked before calling the constructor function for `bootstrap.Application`. Here, the `ConfigureFiber` and `ConfigureGreeter` functions are specified; those are defined by the `modules` package.
79+
80+
81+
### Configure and register the Fiber instance
82+
83+
The `ConfigureFiber` function sets up the Fiber application and registers it as a singleton service within the Parsley framework:
84+
85+
```go
86+
package modules
87+
88+
import (
89+
"github.com/gofiber/fiber/v2"
90+
"github.com/matzefriedrich/parsley/pkg/registration"
91+
"github.com/matzefriedrich/parsley/pkg/types"
92+
)
93+
94+
var _ types.ModuleFunc = ConfigureFiber
95+
96+
func ConfigureFiber(registry types.ServiceRegistry) error {
97+
registration.RegisterInstance(registry, fiber.Config{
98+
AppName: "parsley-app-recipe",
99+
Immutable: true,
100+
})
101+
102+
registry.Register(newFiber, types.LifetimeSingleton)
103+
registry.RegisterModule(RegisterRouteHandlers)
104+
105+
return nil
106+
}
107+
108+
func newFiber(config fiber.Config) *fiber.App {
109+
return fiber.New(config)
110+
}
111+
112+
```
113+
114+
This configuration ensures that the Fiber instance is initialized and available for dependency injection.
115+
116+
117+
### Define and register the application service(s)
118+
119+
The `Greeter` service generates greeting messages based on input parameters. In the recipe example application, this service is a dependency required by the handler of the `say-hello` route.
120+
121+
```go
122+
package services
123+
124+
import "fmt"
125+
126+
type Greeter interface {
127+
SayHello(name string, polite bool) string
128+
}
129+
130+
type greeter struct{}
131+
132+
func (g *greeter) SayHello(name string, polite bool) string {
133+
if polite {
134+
return fmt.Sprintf("Good day, %s!\n", name)
135+
}
136+
return fmt.Sprintf("Hi, %s\n", name)
137+
}
138+
139+
func NewGreeter() Greeter {
140+
return &greeter{}
141+
}
142+
```
143+
144+
The `Greeter` service is registered by the `ConfigureGreeter` service registration module:
145+
146+
```go
147+
package modules
148+
149+
import (
150+
"github.com/gofiber/recipes/parsley-app/internal/services"
151+
152+
"github.com/matzefriedrich/parsley/pkg/types"
153+
)
154+
155+
func ConfigureGreeter(registry types.ServiceRegistry) error {
156+
registry.Register(services.NewGreeterFactory, types.LifetimeTransient)
157+
return nil
158+
}
159+
```
160+
161+
This setup allows the `Greeter` service to be injected wherever needed within the application.
162+
163+
164+
### Implement and register route handlers
165+
166+
Route handlers in this example are services that implement the `RouteHandler` interface, allowing them to register routes with the Fiber application.
167+
168+
```go
169+
package route_handlers
170+
171+
import (
172+
"strconv"
173+
174+
"github.com/gofiber/recipes/parsley-app/internal/services"
175+
176+
"github.com/gofiber/fiber/v2"
177+
)
178+
179+
type greeterRouteHandler struct {
180+
greeter services.Greeter
181+
}
182+
183+
const defaultPoliteFlag = "true"
184+
185+
func (h *greeterRouteHandler) Register(app *fiber.App) {
186+
app.Get("/say-hello", h.HandleSayHelloRequest)
187+
}
188+
189+
func (h *greeterRouteHandler) HandleSayHelloRequest(ctx *fiber.Ctx) error {
190+
191+
name := ctx.Query("name")
192+
193+
politeFlag := ctx.Query("polite", defaultPoliteFlag)
194+
polite, _ := strconv.ParseBool(politeFlag)
195+
196+
msg := h.greeter.SayHello(name, polite)
197+
return ctx.Status(fiber.StatusOK).Send([]byte(msg))
198+
}
199+
200+
var _ RouteHandler = &greeterRouteHandler{}
201+
202+
func NewGreeterRouteHandler(greeter services.Greeter) RouteHandler {
203+
return &greeterRouteHandler{
204+
greeter: greeter,
205+
}
206+
}
207+
```
208+
209+
This handler responds to GET requests at `/say-hello` with a greeting message, utilizing the `Greeter` service injected via the constructor function.
210+
211+
212+
## Run the application
213+
214+
To start the application, execute:
33215

34-
## Running the Example
216+
```sh
217+
go run ./cmd/main.go
218+
```
35219

36-
To run this example:
220+
Once running, you can test the `say-hello` endpoint via the browser, or from the terminal using `curl`. For this recipe, the default listening port is `5502`:
37221

38-
* Clone the repository and navigate to the example directory.
39-
* Run `go run main.go` to start the application.
40-
* Access the application by navigating to `http://localhost:5502/say-hello?name=YourName`. This will return a greeting message, demonstrating the integration of Parsley with GoFiber.
222+
```sh
223+
curl http://localhost:5502/say-hello?name=YourName&polite=true
224+
```

parsley/cmd/main.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ package main
33
import (
44
"context"
55

6-
"parsley-app/internal"
7-
"parsley-app/internal/modules"
8-
6+
"github.com/gofiber/recipes/parsley-app/internal"
7+
"github.com/gofiber/recipes/parsley-app/internal/modules"
98
"github.com/matzefriedrich/parsley/pkg/bootstrap"
109
)
1110

1211
func main() {
13-
context := context.Background()
12+
13+
ctx := context.Background()
1414

1515
// Runs a Fiber instance as a Parsley-enabled app
16-
bootstrap.RunParsleyApplication(context, internal.NewApp,
16+
bootstrap.RunParsleyApplication(ctx, internal.NewApp,
1717
modules.ConfigureFiber,
1818
modules.ConfigureGreeter)
1919
}

parsley/go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
module parsley-app
1+
module github.com/gofiber/recipes/parsley-app
22

33
go 1.23.0
44

55
require (
66
github.com/gofiber/fiber/v2 v2.52.8
7-
github.com/matzefriedrich/parsley v0.8.3
7+
github.com/matzefriedrich/parsley v1.0.12
88
)
99

1010
require (
1111
github.com/andybalholm/brotli v1.1.1 // indirect
1212
github.com/google/uuid v1.6.0 // indirect
1313
github.com/klauspost/compress v1.18.0 // indirect
14-
github.com/mattn/go-colorable v0.1.13 // indirect
14+
github.com/mattn/go-colorable v0.1.14 // indirect
1515
github.com/mattn/go-isatty v0.0.20 // indirect
1616
github.com/mattn/go-runewidth v0.0.16 // indirect
17-
github.com/rivo/uniseg v0.2.0 // indirect
17+
github.com/rivo/uniseg v0.4.7 // indirect
1818
github.com/valyala/bytebufferpool v1.0.0 // indirect
1919
github.com/valyala/fasthttp v1.62.0 // indirect
2020
golang.org/x/sys v0.33.0 // indirect

parsley/go.sum

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,27 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
88
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
99
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
1010
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
11-
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
12-
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
13-
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
11+
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
12+
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
1413
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
1514
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
1615
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
1716
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
18-
github.com/matzefriedrich/parsley v0.8.3 h1:PP9wBkekoHLn6JLHMubwk95KhP0mpgrIGx9Y2ELdsaQ=
19-
github.com/matzefriedrich/parsley v0.8.3/go.mod h1:9ZFeuhRK7Zke2CLkn3NvGF2POOj9gZhWlvKoE7ZYAxY=
17+
github.com/matzefriedrich/parsley v1.0.12 h1:W1fU77+w86d1g9bhRS+2aGZayJIqxFuEHM9jHV05ofU=
18+
github.com/matzefriedrich/parsley v1.0.12/go.mod h1:dphuivszz/gUobbZHpI3nkAP71gSTtIl7jcZsYPRNjc=
2019
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2120
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
22-
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
2321
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
24-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
25-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
22+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
23+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
24+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
25+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
2626
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
2727
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
2828
github.com/valyala/fasthttp v1.62.0 h1:8dKRBX/y2rCzyc6903Zu1+3qN0H/d2MsxPPmVNamiH0=
2929
github.com/valyala/fasthttp v1.62.0/go.mod h1:FCINgr4GKdKqV8Q0xv8b+UxPV+H/O5nNFo3D+r54Htg=
3030
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
3131
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
32-
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3332
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3433
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
3534
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=

parsley/internal/application.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package internal
33
import (
44
"context"
55

6-
"parsley-app/internal/route_handlers"
6+
"github.com/gofiber/recipes/parsley-app/internal/route_handlers"
77

88
"github.com/gofiber/fiber/v2"
99
"github.com/matzefriedrich/parsley/pkg/bootstrap"

parsley/internal/modules/greeter_module.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package modules
22

33
import (
4-
"parsley-app/internal/services"
5-
4+
"github.com/gofiber/recipes/parsley-app/internal/services"
65
"github.com/matzefriedrich/parsley/pkg/types"
76
)
87

parsley/internal/modules/route_handlers_module.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package modules
22

33
import (
4-
"parsley-app/internal/route_handlers"
5-
4+
"github.com/gofiber/recipes/parsley-app/internal/route_handlers"
65
"github.com/matzefriedrich/parsley/pkg/features"
76
"github.com/matzefriedrich/parsley/pkg/registration"
87
"github.com/matzefriedrich/parsley/pkg/types"

parsley/internal/route_handlers/greeter.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ package route_handlers
33
import (
44
"strconv"
55

6-
"parsley-app/internal/services"
7-
86
"github.com/gofiber/fiber/v2"
7+
"github.com/gofiber/recipes/parsley-app/internal/services"
98
)
109

1110
type greeterRouteHandler struct {
@@ -21,6 +20,7 @@ func (h *greeterRouteHandler) Register(app *fiber.App) {
2120

2221
// HandleSayHelloRequest Handles "GET /say-hello" requests.
2322
func (h *greeterRouteHandler) HandleSayHelloRequest(ctx *fiber.Ctx) error {
23+
2424
name := ctx.Query("name")
2525

2626
politeFlag := ctx.Query("polite", defaultPoliteFlag)

0 commit comments

Comments
 (0)