Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: WEOS-1133 As a user I should be able to get a list of items for a content type #60

Merged
merged 37 commits into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9ba9180
Merge remote-tracking branch 'origin/feature/WEOS-1135' into feature/…
shaniah868 Jan 21, 2022
dd4f194
feature: WEOS-1133 Generate BDD Test
shaniah868 Jan 21, 2022
37bb4be
feature: WEOS-1133 Generate BDD Test
shaniah868 Jan 21, 2022
8494aff
feature: WEOS-1133 Create a list method on projection and helper func…
shaniah868 Jan 21, 2022
11d60e3
feature: WEOS-1133 Create a list method on projection
shaniah868 Jan 21, 2022
68ff333
feature: WEOS-1133 Create a list method on projection and add helper …
shaniah868 Jan 21, 2022
beb89c7
feature: WEOS-1133 Create a list method on projection and helper func…
shaniah868 Jan 21, 2022
c492e91
feature: WEOS-1133 Update the List Controller to call the projections
shaniah868 Jan 21, 2022
c819896
Merge pull request #54 from wepala/WEOS-1267
RandyDeo Jan 24, 2022
5e76c81
Merge branch 'feature/WEOS-1133' into WEOS-1266
shaniah868 Jan 24, 2022
357b322
feature: WEOS-1133 Update the List Controller to call the projections
shaniah868 Jan 24, 2022
9ce057b
Merge branch 'WEOS-1266' into WEOS-1265
shaniah868 Jan 24, 2022
f8e2579
Merge pull request #57 from wepala/WEOS-1266
atoniaw Jan 24, 2022
efa1993
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 24, 2022
55d5b66
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 24, 2022
2fe7262
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 24, 2022
45cd35c
Merge branch 'feature/WEOS-1125' into WEOS-1265
atoniaw Jan 24, 2022
03012ae
WEOS-1265 minor fixes in feature file
atoniaw Jan 24, 2022
e0e4edf
WEOS-1265 reverted feature file change
atoniaw Jan 24, 2022
9cbe862
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 25, 2022
2ff01bc
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 25, 2022
13ffd47
Merge remote-tracking branch 'origin/feature/WEOS-1132' into feature/…
shaniah868 Jan 25, 2022
2702962
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 25, 2022
c0c0483
Merge branch 'feature/WEOS-1133' into WEOS-1265
shaniah868 Jan 25, 2022
a1260ea
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 25, 2022
1466679
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 25, 2022
3f1e582
Merge pull request #58 from wepala/WEOS-1265
atoniaw Jan 25, 2022
e1a0856
Merge branch 'dev' into feature/WEOS-1133
akeemphilbert Jan 27, 2022
5a5853b
Merge branch 'dev' into feature/WEOS-1133
shaniah868 Jan 28, 2022
1d59c65
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 28, 2022
270e4f8
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 28, 2022
f11da51
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 28, 2022
a0b1735
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 28, 2022
2c43e79
feature: WEOS-1133 Generate and ensure BDD test passes
shaniah868 Jan 28, 2022
f7173ee
docs: Updated spec to use generated ids in the fixture
akeemphilbert Jan 28, 2022
5bd0dc6
feature: WEOS-1133 Fix BDD
akeemphilbert Jan 28, 2022
a8d522d
Merge branch 'dev' into feature/WEOS-1133
akeemphilbert Jan 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ paths:
operationId: Get Blogs
summary: Get List of Blogs
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: l
x-alias: limit
schema:
type: integer
- in: query
name: filters
schema:
Expand Down
63 changes: 62 additions & 1 deletion controllers/rest/controller_standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,70 @@ func (c *StandardControllers) View(app model.Service, spec *openapi3.Swagger, pa
}

func (c *StandardControllers) List(app model.Service, spec *openapi3.Swagger, path *openapi3.PathItem, operation *openapi3.Operation) echo.HandlerFunc {
var contentType string
var contentTypeSchema *openapi3.SchemaRef
//get the entity information based on the Content Type associated with this operation
for _, respContent := range operation.Responses.Get(http.StatusOK).Value.Content {
//use the first schema ref to determine the entity type
if respContent.Schema.Value.Properties["items"] != nil {
contentType = strings.Replace(respContent.Schema.Value.Properties["items"].Value.Items.Ref, "#/components/schemas/", "", -1)
//get the schema details from the swagger file
contentTypeSchema = spec.Components.Schemas[contentType]
break
} else {
//if items are named differently the alias is checked
var alias string
for _, prop := range respContent.Schema.Value.Properties {
aliasInterface := prop.Value.ExtensionProps.Extensions[AliasExtension]
if aliasInterface != nil {
bytesContext := aliasInterface.(json.RawMessage)
json.Unmarshal(bytesContext, &alias)
if alias == "items" {
if prop.Value.Type == "array" && prop.Value.Items != nil && strings.Contains(prop.Value.Items.Ref, "#/components/schemas/") {
contentType = strings.Replace(prop.Value.Items.Ref, "#/components/schemas/", "", -1)
contentTypeSchema = spec.Components.Schemas[contentType]
break
}
}
}

}
}
}
return func(ctxt echo.Context) error {
newContext := ctxt.Request().Context()
if contentType != "" && contentTypeSchema.Value != nil {
newContext = context.WithValue(newContext, context2.CONTENT_TYPE, &context2.ContentType{
Name: contentType,
Schema: contentTypeSchema.Value,
})
}
//gets the limit and page from context
limit, _ := newContext.Value("limit").(int)
page, _ := newContext.Value("page").(int)
if page == 0 {
page = 1
}
var count int64
var err error
var contentEntities []map[string]interface{}
// sort by default is by id
sorts := map[string]string{"id": "asc"}

return ctxt.JSON(http.StatusOK, "List Items")
for _, projection := range app.Projections() {
if projection != nil {
contentEntities, count, err = projection.GetContentEntities(newContext, page, limit, "", sorts, nil)
}
}
if err != nil {
return NewControllerError(err.Error(), err, http.StatusBadRequest)
}
resp := ListApiResponse{
Total: count,
Page: page,
Items: contentEntities,
}
return ctxt.JSON(http.StatusOK, resp)
}
}

Expand Down
48 changes: 40 additions & 8 deletions controllers/rest/controller_standard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,26 +595,31 @@ func TestStandardControllers_List(t *testing.T) {
e := echo.New()
restAPI := &rest.RESTAPI{}

dispatcher := &DispatcherMock{
DispatchFunc: func(ctx context.Context, command *model.Command) error {
return nil
mockBlog := map[string]interface{}{"id": "123", "title": "my first blog", "description": "description"}
mockBlog1 := map[string]interface{}{"id": "1234", "title": "my first blog1", "description": "description1"}

array := []map[string]interface{}{}
array = append(array, mockBlog, mockBlog1)

mockProjection := &ProjectionMock{
GetContentEntitiesFunc: func(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]map[string]interface{}, int64, error) {
return array, 2, nil
},
}

application := &ApplicationMock{
DispatcherFunc: func() model.Dispatcher {
return dispatcher
ProjectionsFunc: func() []model.Projection {
return []model.Projection{mockProjection}
},
}

//initialization will instantiate with application so we need to overwrite with our mock application
restAPI.Application = application

t.Run("Testing the generic list endpoint", func(t *testing.T) {
t.Run("Testing the generic list endpoint with parameters", func(t *testing.T) {
path := swagger.Paths.Find("/blogs")
controller := restAPI.List(restAPI.Application, swagger, path, path.Get)
resp := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/blogs", nil)
req := httptest.NewRequest(http.MethodGet, "/blogs?page=1&l=5", nil)
mw := rest.Context(restAPI.Application, swagger, path, path.Get)
e.GET("/blogs", controller, mw)
e.ServeHTTP(resp, req)
Expand All @@ -625,5 +630,32 @@ func TestStandardControllers_List(t *testing.T) {
if response.StatusCode != 200 {
t.Errorf("expected response code to be %d, got %d", 200, response.StatusCode)
}
//check response body is a list of content entities
var result rest.ListApiResponse
json.NewDecoder(response.Body).Decode(&result)
if len(result.Items) != 2 {
t.Fatal("expected entities found")
}
if result.Total != 2 {
t.Errorf("expected total to be %d got %d", 2, result.Total)
}
if result.Page != 1 {
t.Errorf("expected page to be %d got %d", 1, result.Page)
}
found := 0
for _, blog := range result.Items {
if blog["id"] == "123" && blog["title"] == "my first blog" && blog["description"] == "description" {
found++
continue
}
if blog["id"] == "1234" && blog["title"] == "my first blog1" && blog["description"] == "description1" {
found++
continue
}
}
if found != 2 {
t.Errorf("expected to find %d got %d", 2, found)
}

})
}
8 changes: 8 additions & 0 deletions controllers/rest/dtos.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ type Rest struct {
PreMiddleware []string `json:"pre-middleware"`
}

//HealthCheckResponse used int he health check controller to return a response with version
type HealthCheckResponse struct {
Version string `json:"version"`
}

//ListApiResponse used in the list controller to return a response with total, page and items retrieved
type ListApiResponse struct {
Total int64 `json:"total"`
Page int `json:"page"`
Items []map[string]interface{} `json:"items"`
}
9 changes: 9 additions & 0 deletions controllers/rest/fixtures/blog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ paths:
operationId: Get Blogs
summary: Get List of Blogs
parameters:
- in: query
name: page
schema:
type: integer
- in: query
name: l
x-alias: limit
schema:
type: integer
- in: query
name: filters
schema:
Expand Down
7 changes: 7 additions & 0 deletions controllers/rest/middleware_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func parseParams(c echo.Context, cc context.Context, parameter *openapi3.Paramet
return nil, err
}
}
//if there is an alias name specified use that instead. The value is a json.RawMessage (not a string)
if tcontextName, ok := parameter.Value.ExtensionProps.Extensions[AliasExtension]; ok {
err := json.Unmarshal(tcontextName.(json.RawMessage), &contextName)
if err != nil {
return nil, err
}
}
var val interface{}
switch strings.ToLower(parameter.Value.In) {
//parameter values stored as strings
Expand Down
25 changes: 25 additions & 0 deletions controllers/rest/middleware_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,29 @@ func TestContext(t *testing.T) {
e.POST("/blogs", handler)
e.ServeHTTP(resp, req)
})
t.Run("parameter in query string that has an alias should be added to context", func(t *testing.T) {
paramName := "l"
alias := "limit"
paramValue := "2"
pValue := 2
path := swagger.Paths.Find("/blogs")
mw := rest.Context(nil, swagger, path, path.Get)
handler := mw(func(ctxt echo.Context) error {
//check that certain parameters are in the context
cc := ctxt.Request().Context()
if cc.Value(alias) == nil {
t.Fatalf("expected a value to be returned for '%s'", paramName)
}
tValue := cc.Value(alias).(int)
if tValue != pValue {
t.Errorf("expected the param '%s' to have value '%s', got '%v'", paramName, paramValue, tValue)
}
return nil
})
e := echo.New()
resp := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/blogs?"+paramName+"="+paramValue, nil)
e.GET("/blogs", handler)
e.ServeHTTP(resp, req)
})
}
24 changes: 14 additions & 10 deletions controllers/rest/middleware_initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,17 +238,19 @@ func AddStandardController(e *echo.Echo, pathData *openapi3.PathItem, method str
//check for identifiers
if identifiers != nil && len(identifiers) > 0 {
for _, identifier := range identifiers {
foundIdentifier := false
//check the parameters for the identifiers
for _, param := range pathData.Put.Parameters {
cName := param.Value.ExtensionProps.Extensions[ContextNameExtension]
if identifier == param.Value.Name || (cName != nil && identifier == cName.(string)) {
foundIdentifier = true
break
}
if !(identifier == param.Value.Name) && !(cName != nil && identifier == cName.(string)) {
allParam = false
e.Logger.Warnf("unexpected error: a parameter for each part of the identifier must be set")
return autoConfigure, nil
}
}
if !foundIdentifier {
allParam = false
e.Logger.Warnf("unexpected error: a parameter for each part of the identifier must be set")
return autoConfigure, nil
}
}
if allParam {
Expand Down Expand Up @@ -356,17 +358,19 @@ func AddStandardController(e *echo.Echo, pathData *openapi3.PathItem, method str
var contextName string
if identifiers != nil && len(identifiers) > 0 {
for _, identifier := range identifiers {
foundIdentifier := false
//check the parameters
for _, param := range pathData.Get.Parameters {
cName := param.Value.ExtensionProps.Extensions[ContextNameExtension]
if identifier == param.Value.Name || (cName != nil && identifier == cName.(string)) {
foundIdentifier = true
break
}
if !(identifier == param.Value.Name) && !(cName != nil && identifier == cName.(string)) {
allParam = false
e.Logger.Warnf("unexpected error: a parameter for each part of the identifier must be set")
return autoConfigure, nil
}
}
if !foundIdentifier {
allParam = false
e.Logger.Warnf("unexpected error: a parameter for each part of the identifier must be set")
return autoConfigure, nil
}
}
}
Expand Down
Loading