Skip to content

Commit

Permalink
Implement basic expansions
Browse files Browse the repository at this point in the history
  • Loading branch information
brandur committed Jun 23, 2017
1 parent 754b9fd commit 0bdbfc5
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 45 deletions.
32 changes: 28 additions & 4 deletions generator.go
Expand Up @@ -2,10 +2,12 @@ package main

import (
"fmt"
"sort"
"strings"
)

var notSupportedErr = fmt.Errorf("Expected response to be a list or include $ref")
var errExpansionNotSupported = fmt.Errorf("Expansion not supported")
var errNotSupported = fmt.Errorf("Expected response to be a list or include $ref")

type DataGenerator struct {
definitions map[string]*JSONSchema
Expand Down Expand Up @@ -38,7 +40,7 @@ func (g *DataGenerator) generateResource(schema *JSONSchema) (interface{}, error
return map[string]interface{}{}, nil
}
}
return nil, notSupportedErr
return nil, errNotSupported
}

// Support schemas with no type annotation at all
Expand All @@ -63,6 +65,15 @@ func (g *DataGenerator) generateInternal(schema *JSONSchema, requestPath string,
return nil, err
}

// Determine if the requested expansions are possible
if expansions != nil {
for key, _ := range expansions.expansions {
if sort.SearchStrings(schema.XExpandableFields, key) == -1 {
return nil, errExpansionNotSupported
}
}
}

data, err := g.generateResource(schema)
if err != nil {
return nil, err
Expand All @@ -80,8 +91,21 @@ func (g *DataGenerator) generateInternal(schema *JSONSchema, requestPath string,

for key, property := range schema.Properties {
dataMap := data.(map[string]interface{})
keyData, err := g.generateInternal(property, requestPath, expansions, dataMap[key])
if err == notSupportedErr {

subSchema := property

var subExpansions *ExpansionLevel
if expansions != nil {
var ok bool
subExpansions, ok = expansions.expansions[key]
if ok {
subSchema = property.XExpansionResources[0]
}
}

keyData, err := g.generateInternal(
subSchema, requestPath, subExpansions, dataMap[key])
if err == errNotSupported {
continue
}
if err != nil {
Expand Down
12 changes: 11 additions & 1 deletion generator_test.go
Expand Up @@ -36,12 +36,22 @@ func TestGenerateResponseData(t *testing.T) {
generator = DataGenerator{testSpec.Definitions, testFixtures}
data, err = generator.Generate(
&JSONSchema{Ref: "#/definitions/charge"}, "", nil)

assert.Nil(t, err)
assert.Equal(t,
testFixtures.Resources["charge"].(map[string]interface{})["id"],
data.(map[string]interface{})["id"])

// expansion
generator = DataGenerator{testSpec.Definitions, testFixtures}
data, err = generator.Generate(
&JSONSchema{Ref: "#/definitions/charge"},
"",
&ExpansionLevel{expansions: map[string]*ExpansionLevel{"customer": nil}})
assert.Nil(t, err)
assert.Equal(t,
testFixtures.Resources["customer"].(map[string]interface{})["id"],
data.(map[string]interface{})["customer"].(map[string]interface{})["id"])

// list
generator = DataGenerator{testSpec.Definitions, testFixtures}
data, err = generator.Generate(listSchema, "/v1/charges", nil)
Expand Down
54 changes: 54 additions & 0 deletions main_test.go
@@ -1,3 +1,57 @@
package main

import ()

var chargeAllMethod *OpenAPIMethod
var chargeCreateMethod *OpenAPIMethod
var chargeDeleteMethod *OpenAPIMethod
var chargeGetMethod *OpenAPIMethod
var testSpec *OpenAPISpec
var testFixtures *Fixtures

func init() {
chargeAllMethod = &OpenAPIMethod{}
chargeCreateMethod = &OpenAPIMethod{}
chargeDeleteMethod = &OpenAPIMethod{}
chargeGetMethod = &OpenAPIMethod{}

testFixtures =
&Fixtures{
Resources: map[ResourceID]interface{}{
ResourceID("charge"): map[string]interface{}{"id": "ch_123"},
ResourceID("customer"): map[string]interface{}{"id": "cus_123"},
},
}

testSpec = &OpenAPISpec{
Definitions: map[string]*JSONSchema{
"charge": {
Properties: map[string]*JSONSchema{
// Normally a customer ID, but expandable to a full
// customer resource
"customer": {
Type: []string{"string"},
XExpansionResources: []*JSONSchema{
&JSONSchema{Ref: "#/definitions/customer"},
},
},
},
XExpandableFields: []string{"customer"},
XResourceID: "charge",
},
"customer": {
XResourceID: "customer",
},
},
Paths: map[OpenAPIPath]map[HTTPVerb]*OpenAPIMethod{
OpenAPIPath("/v1/charges"): {
"get": chargeAllMethod,
"post": chargeCreateMethod,
},
OpenAPIPath("/v1/charges/{id}"): {
"get": chargeGetMethod,
"delete": chargeDeleteMethod,
},
},
}
}
39 changes: 0 additions & 39 deletions server_test.go
Expand Up @@ -8,45 +8,6 @@ import (
assert "github.com/stretchr/testify/require"
)

var chargeAllMethod *OpenAPIMethod
var chargeCreateMethod *OpenAPIMethod
var chargeDeleteMethod *OpenAPIMethod
var chargeGetMethod *OpenAPIMethod
var testSpec *OpenAPISpec
var testFixtures *Fixtures

func init() {
chargeAllMethod = &OpenAPIMethod{}
chargeCreateMethod = &OpenAPIMethod{}
chargeDeleteMethod = &OpenAPIMethod{}
chargeGetMethod = &OpenAPIMethod{}

testFixtures =
&Fixtures{
Resources: map[ResourceID]interface{}{
ResourceID("charge"): map[string]interface{}{"id": "ch_123"},
},
}

testSpec = &OpenAPISpec{
Definitions: map[string]*JSONSchema{
"charge": {XResourceID: "charge"},
},
Paths: map[OpenAPIPath]map[HTTPVerb]*OpenAPIMethod{
OpenAPIPath("/v1/charges"): {
"get": chargeAllMethod,
"post": chargeCreateMethod,
},
OpenAPIPath("/v1/charges/{id}"): {
"get": chargeGetMethod,
"delete": chargeDeleteMethod,
},
},
}
}

// ---

func TestStubServerRouteRequest(t *testing.T) {
server := &StubServer{spec: testSpec}
server.initializeRouter()
Expand Down
4 changes: 3 additions & 1 deletion spec.go
Expand Up @@ -16,7 +16,9 @@ type JSONSchema struct {
// it defines the location of the actual schema definition.
Ref string `json:"$ref"`

XResourceID string `json:"x-resourceId"`
XExpandableFields []string `json:"x-expandableFields"`
XExpansionResources []*JSONSchema `json:"x-expansionResources"`
XResourceID string `json:"x-resourceId"`
}

type OpenAPIParameter struct {
Expand Down

0 comments on commit 0bdbfc5

Please sign in to comment.