Repository navigation
Expand file tree
/
Copy pathserver.go
More file actions
199 lines (169 loc) · 5.13 KB
/
Copy pathserver.go
File metadata and controls
199 lines (169 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Package server implements HTTP handlers for the user API.
//
//nolint:nilerr,ireturn // the strict interface returns interfaces, and each failure is a typed error response with a nil error
package server
import (
"context"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/tabmadi/go-oapi-sqlc-example/internal/config"
"github.com/tabmadi/go-oapi-sqlc-example/internal/gen/oapi"
"github.com/tabmadi/go-oapi-sqlc-example/internal/repository"
)
// Server handles HTTP requests for user operations.
type Server struct {
repo *repository.UserRepository
app *fiber.App
cfg *config.Config
}
// Ensure that Server implements the StrictServerInterface interface at compile time.
var _ oapi.StrictServerInterface = (*Server)(nil)
// NewServer creates a new Server instance with the given repository.
func NewServer(cfg *config.Config, repo *repository.UserRepository) *Server {
app := fiber.New(fiber.Config{
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
IdleTimeout: cfg.IdleTimeout,
})
app.Use(logger.New())
app.Use(recover.New())
srv := &Server{
repo: repo,
app: app,
cfg: cfg,
}
strict := oapi.NewStrictHandler(srv, nil)
oapi.RegisterHandlers(app, strict)
return srv
}
// Start serves requests until the process gets SIGINT or SIGTERM. It then shuts down within the shutdown timeout.
func (s *Server) Start() {
serverErrors := make(chan error, 1)
go func() {
log.Printf("Starting server on %s", s.cfg.ListenAddress)
serverErrors <- s.app.Listen(s.cfg.ListenAddress)
}()
shutdown := make(chan os.Signal, 1)
signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)
select {
case err := <-serverErrors:
log.Fatalf("Error starting server: %v", err)
case <-shutdown:
err := s.app.ShutdownWithTimeout(s.cfg.ShutdownTimeout)
if err != nil {
log.Printf("Error during server shutdown: %v", err)
}
log.Println("Server gracefully stopped")
}
}
// ListUsers handles GET /users requests to retrieve a list of users.
func (s *Server) ListUsers(
ctx context.Context,
request oapi.ListUsersRequestObject,
) (oapi.ListUsersResponseObject, error) {
users, err := s.repo.List(ctx, request.Params)
if err != nil {
return oapi.ListUsers500JSONResponse{
ErrorJSONResponse: oapi.ErrorJSONResponse{
Code: http.StatusInternalServerError,
Message: err.Error(),
},
}, nil
}
return oapi.ListUsers200JSONResponse(users), nil
}
// CreateUser handles POST /users requests to create a new user.
func (s *Server) CreateUser(
ctx context.Context,
request oapi.CreateUserRequestObject,
) (oapi.CreateUserResponseObject, error) {
if request.Body == nil {
return oapi.CreateUser400JSONResponse{
BadRequestJSONResponse: oapi.BadRequestJSONResponse{
Code: http.StatusBadRequest,
Message: "invalid request body",
},
}, nil
}
user, err := s.repo.Create(ctx, *request.Body)
if err != nil {
return oapi.CreateUser500JSONResponse{
ErrorJSONResponse: oapi.ErrorJSONResponse{
Code: http.StatusInternalServerError,
Message: err.Error(),
},
}, nil
}
return oapi.CreateUser201JSONResponse(*user), nil
}
// GetUserByID handles GET /users/{id} requests to retrieve a specific user.
func (s *Server) GetUserByID(
ctx context.Context,
request oapi.GetUserByIDRequestObject,
) (oapi.GetUserByIDResponseObject, error) {
user, err := s.repo.Get(ctx, request.Id)
if err != nil {
return oapi.GetUserByID404JSONResponse{
NotFoundJSONResponse: oapi.NotFoundJSONResponse{
Code: http.StatusNotFound,
Message: err.Error(),
},
}, nil
}
return oapi.GetUserByID200JSONResponse(*user), nil
}
// UpdateUser handles PUT /users/{id} requests to update a specific user.
func (s *Server) UpdateUser(
ctx context.Context,
request oapi.UpdateUserRequestObject,
) (oapi.UpdateUserResponseObject, error) {
if request.Body == nil {
return oapi.UpdateUser400JSONResponse{
BadRequestJSONResponse: oapi.BadRequestJSONResponse{
Code: http.StatusBadRequest,
Message: "invalid request body",
},
}, nil
}
user, err := s.repo.Update(ctx, request.Id, *request.Body)
if err != nil {
return oapi.UpdateUser500JSONResponse{
ErrorJSONResponse: oapi.ErrorJSONResponse{
Code: http.StatusInternalServerError,
Message: err.Error(),
},
}, nil
}
return oapi.UpdateUser200JSONResponse(*user), nil
}
// DeleteUser handles DELETE /users/{id} requests to delete a specific user.
func (s *Server) DeleteUser(
ctx context.Context,
request oapi.DeleteUserRequestObject,
) (oapi.DeleteUserResponseObject, error) {
err := s.repo.Delete(ctx, request.Id)
if err != nil {
if errors.Is(err, repository.ErrRecordNotFound) {
return oapi.DeleteUser404JSONResponse{
NotFoundJSONResponse: oapi.NotFoundJSONResponse{
Code: http.StatusNotFound,
Message: "User not found",
},
}, nil
}
return oapi.DeleteUser500JSONResponse{
ErrorJSONResponse: oapi.ErrorJSONResponse{
Code: http.StatusInternalServerError,
Message: "Failed to delete user: " + err.Error(),
},
}, nil
}
return oapi.DeleteUser204Response{}, nil
}