Skip to content

Commit 14646aa

Browse files
authored
refactor: move base URL into database context, use gorm hooks for links (#564)
With this, gorm hooks are used to set the links for resources. This removes a lot of unnecessary wrapper code and gets rid of many unnecessary database queries. Especially for the month endpoint, this should result in noticable performance improvements.
1 parent 765c63c commit 14646aa

34 files changed

+1597
-1634
lines changed

api/docs.go

Lines changed: 398 additions & 422 deletions
Large diffs are not rendered by default.

api/swagger.json

Lines changed: 398 additions & 422 deletions
Large diffs are not rendered by default.

api/swagger.yaml

Lines changed: 294 additions & 311 deletions
Large diffs are not rendered by default.

main.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"io"
66
"net/http"
7+
"net/url"
78
"os"
89
"os/signal"
910
"syscall"
@@ -45,8 +46,18 @@ func main() {
4546
}
4647
log.Logger = log.Output(output).With().Logger()
4748

49+
// Get the base URL set in the environment
50+
apiURL, ok := os.LookupEnv("API_URL")
51+
if !ok {
52+
log.Fatal().Msg("environment variable API_URL must be set")
53+
}
54+
url, err := url.Parse(apiURL)
55+
if err != nil {
56+
log.Fatal().Msg("environment variable API_URL must be a valid URL")
57+
}
58+
4859
// Create data directory
49-
err := database.CreateDir("data")
60+
err = database.CreateDir("data")
5061
if err != nil {
5162
log.Fatal().Msg(err.Error())
5263
}
@@ -61,9 +72,12 @@ func main() {
6172
log.Fatal().Msg(err.Error())
6273
}
6374

64-
controller := controllers.Controller{DB: db}
75+
// Set the DB context and add it to the controller
76+
ctx := context.Background()
77+
ctx = context.WithValue(ctx, database.ContextURL, url)
78+
controller := controllers.Controller{DB: db.WithContext(ctx)}
6579

66-
r, err := router.Config()
80+
r, err := router.Config(url)
6781
if err != nil {
6882
log.Fatal().Msg(err.Error())
6983
}

pkg/controllers/account.go

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ type AccountResponse struct {
2323
type Account struct {
2424
models.Account
2525
RecentEnvelopes []models.Envelope `json:"recentEnvelopes"`
26-
Links AccountLinks `json:"links"`
27-
}
28-
29-
type AccountLinks struct {
30-
Self string `json:"self" example:"https://example.com/api/v1/accounts/af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"`
31-
Transactions string `json:"transactions" example:"https://example.com/api/v1/transactions?account=af892e10-7e0a-4fb8-b1bc-4b6d88401ed2"`
3226
}
3327

3428
type AccountQueryFilter struct {
@@ -97,13 +91,13 @@ func (co Controller) OptionsAccountList(c *gin.Context) {
9791
// @Param accountId path string true "ID formatted as string"
9892
// @Router /v1/accounts/{accountId} [options]
9993
func (co Controller) OptionsAccountDetail(c *gin.Context) {
100-
p, err := uuid.Parse(c.Param("accountId"))
94+
id, err := uuid.Parse(c.Param("accountId"))
10195
if err != nil {
10296
httperrors.InvalidUUID(c)
10397
return
10498
}
10599

106-
_, ok := co.getAccountObject(c, p)
100+
_, ok := co.getAccountObject(c, id)
107101
if !ok {
108102
return
109103
}
@@ -223,13 +217,13 @@ func (co Controller) GetAccounts(c *gin.Context) {
223217
// @Param accountId path string true "ID formatted as string"
224218
// @Router /v1/accounts/{accountId} [get]
225219
func (co Controller) GetAccount(c *gin.Context) {
226-
p, err := uuid.Parse(c.Param("accountId"))
220+
id, err := uuid.Parse(c.Param("accountId"))
227221
if err != nil {
228222
httperrors.InvalidUUID(c)
229223
return
230224
}
231225

232-
accountObject, ok := co.getAccountObject(c, p)
226+
accountObject, ok := co.getAccountObject(c, id)
233227
if !ok {
234228
return
235229
}
@@ -251,13 +245,13 @@ func (co Controller) GetAccount(c *gin.Context) {
251245
// @Param account body models.AccountCreate true "Account"
252246
// @Router /v1/accounts/{accountId} [patch]
253247
func (co Controller) UpdateAccount(c *gin.Context) {
254-
p, err := uuid.Parse(c.Param("accountId"))
248+
id, err := uuid.Parse(c.Param("accountId"))
255249
if err != nil {
256250
httperrors.InvalidUUID(c)
257251
return
258252
}
259253

260-
account, ok := co.getAccountResource(c, p)
254+
account, ok := co.getAccountResource(c, id)
261255
if !ok {
262256
return
263257
}
@@ -293,13 +287,13 @@ func (co Controller) UpdateAccount(c *gin.Context) {
293287
// @Param accountId path string true "ID formatted as string"
294288
// @Router /v1/accounts/{accountId} [delete]
295289
func (co Controller) DeleteAccount(c *gin.Context) {
296-
p, err := uuid.Parse(c.Param("accountId"))
290+
id, err := uuid.Parse(c.Param("accountId"))
297291
if err != nil {
298292
httperrors.InvalidUUID(c)
299293
return
300294
}
301295

302-
account, ok := co.getAccountResource(c, p)
296+
account, ok := co.getAccountResource(c, id)
303297
if !ok {
304298
return
305299
}
@@ -352,9 +346,5 @@ func (co Controller) getAccountObject(c *gin.Context, id uuid.UUID) (Account, bo
352346
return Account{
353347
account,
354348
recentEnvelopes,
355-
AccountLinks{
356-
Self: fmt.Sprintf("%s/v1/accounts/%s", c.GetString("baseURL"), account.ID),
357-
Transactions: fmt.Sprintf("%s/v1/transactions?account=%s", c.GetString("baseURL"), account.ID),
358-
},
359349
}, true
360350
}

pkg/controllers/allocation.go

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package controllers
22

33
import (
4-
"fmt"
54
"net/http"
65

76
"github.com/google/uuid"
@@ -15,20 +14,11 @@ import (
1514
)
1615

1716
type AllocationResponse struct {
18-
Data Allocation `json:"data"`
17+
Data models.Allocation `json:"data"`
1918
}
2019

2120
type AllocationListResponse struct {
22-
Data []Allocation `json:"data"`
23-
}
24-
25-
type Allocation struct {
26-
models.Allocation
27-
Links AllocationLinks `json:"links"`
28-
}
29-
30-
type AllocationLinks struct {
31-
Self string `json:"self" example:"https://example.com/api/v1/allocations/902cd93c-3724-4e46-8540-d014131282fc"`
21+
Data []models.Allocation `json:"data"`
3222
}
3323

3424
type AllocationQueryFilter struct {
@@ -95,13 +85,13 @@ func (co Controller) OptionsAllocationList(c *gin.Context) {
9585
// @Param allocationId path string true "ID formatted as string"
9686
// @Router /v1/allocations/{allocationId} [options]
9787
func (co Controller) OptionsAllocationDetail(c *gin.Context) {
98-
p, err := uuid.Parse(c.Param("allocationId"))
88+
id, err := uuid.Parse(c.Param("allocationId"))
9989
if err != nil {
10090
httperrors.InvalidUUID(c)
10191
return
10292
}
10393

104-
_, ok := co.getAllocationObject(c, p)
94+
_, ok := co.getAllocationResource(c, id)
10595
if !ok {
10696
return
10797
}
@@ -137,8 +127,7 @@ func (co Controller) CreateAllocation(c *gin.Context) {
137127
return
138128
}
139129

140-
allocationObject, _ := co.getAllocationObject(c, allocation.ID)
141-
c.JSON(http.StatusCreated, AllocationResponse{Data: allocationObject})
130+
c.JSON(http.StatusCreated, AllocationResponse{Data: allocation})
142131
}
143132

144133
// GetAllocations returns a list of allocations matching the search parameters
@@ -181,14 +170,11 @@ func (co Controller) GetAllocations(c *gin.Context) {
181170
// When there are no resources, we want an empty list, not null
182171
// Therefore, we use make to create a slice with zero elements
183172
// which will be marshalled to an empty JSON array
184-
allocationObjects := make([]Allocation, 0)
185-
186-
for _, allocation := range allocations {
187-
o, _ := co.getAllocationObject(c, allocation.ID)
188-
allocationObjects = append(allocationObjects, o)
173+
if len(allocations) == 0 {
174+
allocations = make([]models.Allocation, 0)
189175
}
190176

191-
c.JSON(http.StatusOK, AllocationListResponse{Data: allocationObjects})
177+
c.JSON(http.StatusOK, AllocationListResponse{Data: allocations})
192178
}
193179

194180
// GetAllocation returns data about a specific allocation
@@ -204,13 +190,13 @@ func (co Controller) GetAllocations(c *gin.Context) {
204190
// @Param allocationId path string true "ID formatted as string"
205191
// @Router /v1/allocations/{allocationId} [get]
206192
func (co Controller) GetAllocation(c *gin.Context) {
207-
p, err := uuid.Parse(c.Param("allocationId"))
193+
id, err := uuid.Parse(c.Param("allocationId"))
208194
if err != nil {
209195
httperrors.InvalidUUID(c)
210196
return
211197
}
212198

213-
allocationObject, ok := co.getAllocationObject(c, p)
199+
allocationObject, ok := co.getAllocationResource(c, id)
214200
if !ok {
215201
return
216202
}
@@ -233,13 +219,13 @@ func (co Controller) GetAllocation(c *gin.Context) {
233219
// @Param allocation body models.AllocationCreate true "Allocation"
234220
// @Router /v1/allocations/{allocationId} [patch]
235221
func (co Controller) UpdateAllocation(c *gin.Context) {
236-
p, err := uuid.Parse(c.Param("allocationId"))
222+
id, err := uuid.Parse(c.Param("allocationId"))
237223
if err != nil {
238224
httperrors.InvalidUUID(c)
239225
return
240226
}
241227

242-
allocation, ok := co.getAllocationResource(c, p)
228+
allocation, ok := co.getAllocationResource(c, id)
243229
if !ok {
244230
return
245231
}
@@ -258,8 +244,7 @@ func (co Controller) UpdateAllocation(c *gin.Context) {
258244
return
259245
}
260246

261-
allocationObject, _ := co.getAllocationObject(c, allocation.ID)
262-
c.JSON(http.StatusOK, AllocationResponse{Data: allocationObject})
247+
c.JSON(http.StatusOK, AllocationResponse{Data: allocation})
263248
}
264249

265250
// DeleteAllocation deletes an allocation
@@ -274,13 +259,13 @@ func (co Controller) UpdateAllocation(c *gin.Context) {
274259
// @Param allocationId path string true "ID formatted as string"
275260
// @Router /v1/allocations/{allocationId} [delete]
276261
func (co Controller) DeleteAllocation(c *gin.Context) {
277-
p, err := uuid.Parse(c.Param("allocationId"))
262+
id, err := uuid.Parse(c.Param("allocationId"))
278263
if err != nil {
279264
httperrors.InvalidUUID(c)
280265
return
281266
}
282267

283-
allocation, ok := co.getAllocationResource(c, p)
268+
allocation, ok := co.getAllocationResource(c, id)
284269
if !ok {
285270
return
286271
}
@@ -312,17 +297,3 @@ func (co Controller) getAllocationResource(c *gin.Context, id uuid.UUID) (models
312297

313298
return allocation, true
314299
}
315-
316-
func (co Controller) getAllocationObject(c *gin.Context, id uuid.UUID) (Allocation, bool) {
317-
resource, ok := co.getAllocationResource(c, id)
318-
if !ok {
319-
return Allocation{}, false
320-
}
321-
322-
return Allocation{
323-
resource,
324-
AllocationLinks{
325-
Self: fmt.Sprintf("%s/v1/allocations/%s", c.GetString("baseURL"), id),
326-
},
327-
}, true
328-
}

0 commit comments

Comments
 (0)