Skip to content

Commit c50e787

Browse files
story(issue-2): rest create a package to standardize restful api creation (#5)
* feat(issue-2): define proto package for reusable api types * feat(issue-2): rough out rest package * feat(issue-2): map http codes to status codes * test(issue-2): added cases for readiness endpoint * test(issue-2): added cases for liveness endpoint * chore(docs): updated coverage badge. * chore(issue-2): update bedrock * refactor(issue-2): proto message type constraint was incorrect * refactor(issue-2): use bedrock recover func * chore(docs): updated coverage badge. * test(issue-2): added cases around full on testing health endpoint responses * test(issue-2): added cases for invalid header and invalid query param handling * chore(docs): updated coverage badge. * feat(issue-2): added path param support * test(issue-2): added test case for invalid path parameter * chore(docs): updated coverage badge. * test(issue-2): added cases for missing required parameters * chore(docs): updated coverage badge. * feat(issue-2): register openapi endpoint * feat(issue-2): roughed out petstore example * chore(docs): updated coverage badge. * feat(issue-2): implemented pet store * feat(issue-2): improved rest petstore example * test(issue-2): added tests for petstore inmemory implementation * feat(issue-2): add helpers for getting non request body values * test(issue-2): added cases for petstore endpoints * chore(docs): updated coverage badge. * feat(issue-2): update to latest bedrock version and simplify api usage with protobuf * chore(docs): updated coverage badge. --------- Co-authored-by: GitHub Action <[email protected]>
1 parent 4b1d690 commit c50e787

30 files changed

+4021
-8
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Go Reference](https://pkg.go.dev/badge/github.com/z5labs/humus.svg)](https://pkg.go.dev/github.com/z5labs/humus)
44
[![Go Report Card](https://goreportcard.com/badge/github.com/z5labs/humus)](https://goreportcard.com/report/github.com/z5labs/humus)
5-
![Coverage](https://img.shields.io/badge/Coverage-91.2%25-brightgreen)
5+
![Coverage](https://img.shields.io/badge/Coverage-71.0%25-brightgreen)
66
[![build](https://github.com/z5labs/humus/actions/workflows/build.yaml/badge.svg)](https://github.com/z5labs/humus/actions/workflows/build.yaml)
77

88
**humus one stop shop framework for all Z5Labs projects in Go.**

example/internal/petstore/petstore.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2024 Z5Labs and Contributors
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
package petstore
7+
8+
import (
9+
"context"
10+
"sync"
11+
12+
"github.com/z5labs/humus/example/internal/petstorepb"
13+
14+
"go.opentelemetry.io/otel"
15+
)
16+
17+
type InMemory struct {
18+
mu sync.Mutex
19+
pets map[int64]*petstorepb.Pet
20+
}
21+
22+
func NewInMemory() *InMemory {
23+
return &InMemory{
24+
pets: make(map[int64]*petstorepb.Pet),
25+
}
26+
}
27+
28+
func (s *InMemory) Add(ctx context.Context, pet *petstorepb.Pet) {
29+
_, span := otel.Tracer("pet").Start(ctx, "Store.Add")
30+
defer span.End()
31+
32+
s.mu.Lock()
33+
defer s.mu.Unlock()
34+
35+
s.pets[pet.Id] = pet
36+
}
37+
38+
func (s *InMemory) Get(ctx context.Context, id int64) (*petstorepb.Pet, bool) {
39+
_, span := otel.Tracer("pet").Start(ctx, "Store.Get")
40+
defer span.End()
41+
42+
s.mu.Lock()
43+
defer s.mu.Unlock()
44+
45+
pet, exists := s.pets[id]
46+
return pet, exists
47+
}
48+
49+
func (s *InMemory) Delete(ctx context.Context, id int64) {
50+
_, span := otel.Tracer("pet").Start(ctx, "Store.Delete")
51+
defer span.End()
52+
53+
s.mu.Lock()
54+
defer s.mu.Unlock()
55+
56+
delete(s.pets, id)
57+
}
58+
59+
func (s *InMemory) Pets(ctx context.Context) []*petstorepb.Pet {
60+
_, span := otel.Tracer("pet").Start(ctx, "Store.Pets")
61+
defer span.End()
62+
63+
s.mu.Lock()
64+
defer s.mu.Unlock()
65+
66+
pets := make([]*petstorepb.Pet, 0, len(s.pets))
67+
for _, pet := range s.pets {
68+
pets = append(pets, pet)
69+
}
70+
return pets
71+
}
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (c) 2024 Z5Labs and Contributors
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
package petstore
7+
8+
import (
9+
"context"
10+
"testing"
11+
12+
"github.com/z5labs/humus/example/internal/petstorepb"
13+
14+
"github.com/stretchr/testify/assert"
15+
)
16+
17+
func TestInMemory_Add(t *testing.T) {
18+
t.Run("will add pet to store", func(t *testing.T) {
19+
t.Run("always", func(t *testing.T) {
20+
store := NewInMemory()
21+
22+
store.Add(context.Background(), &petstorepb.Pet{
23+
Id: 1,
24+
})
25+
26+
if !assert.Contains(t, store.pets, int64(1)) {
27+
return
28+
}
29+
})
30+
})
31+
}
32+
33+
func TestInMemory_Get(t *testing.T) {
34+
t.Run("will not return pet", func(t *testing.T) {
35+
t.Run("if there are no pets in the store", func(t *testing.T) {
36+
store := NewInMemory()
37+
38+
pet, found := store.Get(context.Background(), 1)
39+
if !assert.False(t, found) {
40+
return
41+
}
42+
if !assert.Nil(t, pet) {
43+
return
44+
}
45+
})
46+
47+
t.Run("if the pet id is not found", func(t *testing.T) {
48+
store := NewInMemory()
49+
store.pets[1] = &petstorepb.Pet{}
50+
51+
pet, found := store.Get(context.Background(), 2)
52+
if !assert.False(t, found) {
53+
return
54+
}
55+
if !assert.Nil(t, pet) {
56+
return
57+
}
58+
})
59+
})
60+
61+
t.Run("will return pet", func(t *testing.T) {
62+
t.Run("if pet id is found", func(t *testing.T) {
63+
store := NewInMemory()
64+
store.pets[1] = &petstorepb.Pet{}
65+
66+
pet, found := store.Get(context.Background(), 1)
67+
if !assert.True(t, found) {
68+
return
69+
}
70+
if !assert.NotNil(t, pet) {
71+
return
72+
}
73+
})
74+
})
75+
}
76+
77+
func TestInMemory_Delete(t *testing.T) {
78+
t.Run("will delete pet", func(t *testing.T) {
79+
t.Run("if the pet id is found", func(t *testing.T) {
80+
store := NewInMemory()
81+
store.pets[1] = &petstorepb.Pet{}
82+
83+
store.Delete(context.Background(), 1)
84+
if !assert.Empty(t, store.pets) {
85+
return
86+
}
87+
})
88+
})
89+
90+
t.Run("will be a no-op", func(t *testing.T) {
91+
t.Run("if the pet id is not found", func(t *testing.T) {
92+
store := NewInMemory()
93+
94+
store.Delete(context.Background(), 1)
95+
if !assert.Empty(t, store.pets) {
96+
return
97+
}
98+
})
99+
})
100+
}
101+
102+
func TestInMemory_Pets(t *testing.T) {
103+
t.Run("will return pets", func(t *testing.T) {
104+
t.Run("if there are pets in the store", func(t *testing.T) {
105+
store := NewInMemory()
106+
107+
store.pets[1] = &petstorepb.Pet{Id: 1}
108+
store.pets[2] = &petstorepb.Pet{Id: 2}
109+
110+
pets := store.Pets(context.Background())
111+
if !assert.Len(t, pets, 2) {
112+
return
113+
}
114+
})
115+
})
116+
}

0 commit comments

Comments
 (0)