Skip to content

Commit e339682

Browse files
committed
feat: integrate gin-swagger for API documentation generation
1 parent 19f43d1 commit e339682

File tree

9 files changed

+999
-77
lines changed

9 files changed

+999
-77
lines changed

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: fmt build build-api build-consumer lint
1+
.PHONY: fmt build build-api build-consumer lint swagger
22

33
fmt:
44
@echo "Formatting code..."
@@ -20,4 +20,8 @@ test:
2020

2121
lint:
2222
@echo "Running linter..."
23-
@golangci-lint run
23+
@golangci-lint run
24+
25+
swagger:
26+
@echo "Generating swagger documentation..."
27+
@swag init -g cmd/api/main.go -o docs

cmd/api/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,28 @@ import (
66
"log"
77
"net/http"
88

9+
"github.com/BarkinBalci/event-analytics-service/docs"
910
"github.com/BarkinBalci/event-analytics-service/internal/api"
1011
"github.com/BarkinBalci/event-analytics-service/internal/clients"
1112
"github.com/BarkinBalci/event-analytics-service/internal/config"
1213
"github.com/BarkinBalci/event-analytics-service/internal/service"
1314
)
1415

16+
// @title Event Analytics Service API
17+
// @version 1.0
18+
// @description API for publishing and managing analytics events
19+
// @host localhost:8080
20+
// @BasePath /
21+
// @schemes http https
1522
func main() {
1623
cfg, err := config.Load()
1724
if err != nil {
1825
log.Fatalf("Failed to load config: %v", err)
1926
}
2027

28+
// Configure Swagger host dynamically
29+
docs.SwaggerInfo.Host = cfg.ServiceHost
30+
2131
// Initialize SQS client
2232
sqsClient, err := clients.NewSQSClient(context.Background(), cfg.SQSEndpoint, cfg.SQSQueueURL, cfg.SQSRegion)
2333
if err != nil {

docs/docs.go

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
// Package docs Code generated by swaggo/swag. DO NOT EDIT
2+
package docs
3+
4+
import "github.com/swaggo/swag"
5+
6+
const docTemplate = `{
7+
"schemes": {{ marshal .Schemes }},
8+
"swagger": "2.0",
9+
"info": {
10+
"description": "{{escape .Description}}",
11+
"title": "{{.Title}}",
12+
"contact": {},
13+
"version": "{{.Version}}"
14+
},
15+
"host": "{{.Host}}",
16+
"basePath": "{{.BasePath}}",
17+
"paths": {
18+
"/events": {
19+
"post": {
20+
"description": "Publish a single analytics event to the queue",
21+
"consumes": [
22+
"application/json"
23+
],
24+
"produces": [
25+
"application/json"
26+
],
27+
"tags": [
28+
"events"
29+
],
30+
"summary": "Publish a single event",
31+
"parameters": [
32+
{
33+
"description": "Event data",
34+
"name": "event",
35+
"in": "body",
36+
"required": true,
37+
"schema": {
38+
"$ref": "#/definitions/models.PublishEventRequest"
39+
}
40+
}
41+
],
42+
"responses": {
43+
"202": {
44+
"description": "Accepted",
45+
"schema": {
46+
"$ref": "#/definitions/models.PublishEventResponse"
47+
}
48+
},
49+
"400": {
50+
"description": "Bad Request",
51+
"schema": {
52+
"$ref": "#/definitions/models.ErrorResponse"
53+
}
54+
},
55+
"500": {
56+
"description": "Internal Server Error",
57+
"schema": {
58+
"$ref": "#/definitions/models.ErrorResponse"
59+
}
60+
}
61+
}
62+
}
63+
},
64+
"/events/bulk": {
65+
"post": {
66+
"description": "Publish multiple analytics events in bulk to the queue",
67+
"consumes": [
68+
"application/json"
69+
],
70+
"produces": [
71+
"application/json"
72+
],
73+
"tags": [
74+
"events"
75+
],
76+
"summary": "Publish multiple events",
77+
"parameters": [
78+
{
79+
"description": "Bulk events data",
80+
"name": "events",
81+
"in": "body",
82+
"required": true,
83+
"schema": {
84+
"$ref": "#/definitions/models.PublishEventsBulkRequest"
85+
}
86+
}
87+
],
88+
"responses": {
89+
"202": {
90+
"description": "Accepted",
91+
"schema": {
92+
"$ref": "#/definitions/models.PublishBulkEventsResponse"
93+
}
94+
},
95+
"400": {
96+
"description": "Bad Request",
97+
"schema": {
98+
"$ref": "#/definitions/models.ErrorResponse"
99+
}
100+
},
101+
"500": {
102+
"description": "Internal Server Error",
103+
"schema": {
104+
"$ref": "#/definitions/models.ErrorResponse"
105+
}
106+
}
107+
}
108+
}
109+
},
110+
"/health": {
111+
"get": {
112+
"description": "Check if the service is running",
113+
"produces": [
114+
"application/json"
115+
],
116+
"tags": [
117+
"health"
118+
],
119+
"summary": "Health check",
120+
"responses": {
121+
"200": {
122+
"description": "OK",
123+
"schema": {
124+
"type": "object",
125+
"additionalProperties": {
126+
"type": "string"
127+
}
128+
}
129+
}
130+
}
131+
}
132+
}
133+
},
134+
"definitions": {
135+
"models.ErrorResponse": {
136+
"type": "object",
137+
"properties": {
138+
"error": {
139+
"type": "string",
140+
"example": "validation_error"
141+
},
142+
"message": {
143+
"type": "string",
144+
"example": "event_name is required"
145+
}
146+
}
147+
},
148+
"models.PublishBulkEventsResponse": {
149+
"type": "object",
150+
"properties": {
151+
"accepted": {
152+
"type": "integer",
153+
"example": 5
154+
},
155+
"errors": {
156+
"type": "array",
157+
"items": {
158+
"type": "string"
159+
},
160+
"example": [
161+
"validation error on event 3"
162+
]
163+
},
164+
"event_ids": {
165+
"type": "array",
166+
"items": {
167+
"type": "string"
168+
},
169+
"example": [
170+
"evt_1",
171+
"evt_2",
172+
"evt_3"
173+
]
174+
},
175+
"rejected": {
176+
"type": "integer",
177+
"example": 0
178+
}
179+
}
180+
},
181+
"models.PublishEventRequest": {
182+
"type": "object",
183+
"required": [
184+
"channel",
185+
"event_name",
186+
"timestamp",
187+
"user_id"
188+
],
189+
"properties": {
190+
"campaign_id": {
191+
"type": "string",
192+
"example": "cmp_987"
193+
},
194+
"channel": {
195+
"type": "string",
196+
"example": "web"
197+
},
198+
"event_name": {
199+
"type": "string",
200+
"example": "product_view"
201+
},
202+
"metadata": {
203+
"type": "object",
204+
"additionalProperties": {
205+
"type": "string"
206+
},
207+
"example": {
208+
"price": "129.99",
209+
"product_id": "prod-789"
210+
}
211+
},
212+
"tags": {
213+
"type": "array",
214+
"items": {
215+
"type": "string"
216+
},
217+
"example": [
218+
"electronics",
219+
"homepage",
220+
"flash_sale"
221+
]
222+
},
223+
"timestamp": {
224+
"type": "integer",
225+
"example": 1723475612
226+
},
227+
"user_id": {
228+
"type": "string",
229+
"example": "user_123"
230+
}
231+
}
232+
},
233+
"models.PublishEventResponse": {
234+
"type": "object",
235+
"properties": {
236+
"event_id": {
237+
"type": "string",
238+
"example": "evt_1a2b3c4d5e6f"
239+
},
240+
"status": {
241+
"type": "string",
242+
"example": "accepted"
243+
}
244+
}
245+
},
246+
"models.PublishEventsBulkRequest": {
247+
"type": "object",
248+
"required": [
249+
"events"
250+
],
251+
"properties": {
252+
"events": {
253+
"type": "array",
254+
"maxItems": 1000,
255+
"minItems": 1,
256+
"items": {
257+
"$ref": "#/definitions/models.PublishEventRequest"
258+
}
259+
}
260+
}
261+
}
262+
}
263+
}`
264+
265+
// SwaggerInfo holds exported Swagger Info so clients can modify it
266+
var SwaggerInfo = &swag.Spec{
267+
Version: "1.0",
268+
Host: "localhost:8080",
269+
BasePath: "/",
270+
Schemes: []string{"http", "https"},
271+
Title: "Event Analytics Service API",
272+
Description: "API for publishing and managing analytics events",
273+
InfoInstanceName: "swagger",
274+
SwaggerTemplate: docTemplate,
275+
LeftDelim: "{{",
276+
RightDelim: "}}",
277+
}
278+
279+
func init() {
280+
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
281+
}

0 commit comments

Comments
 (0)