Skip to content

Commit

Permalink
Merge pull request #155 from Clever/support-paging-on-put
Browse files Browse the repository at this point in the history
Support paging on put
  • Loading branch information
Kevin Shen authored May 4, 2017
2 parents c049bd0 + b76cd7c commit b33fe8d
Show file tree
Hide file tree
Showing 18 changed files with 945 additions and 19 deletions.
4 changes: 2 additions & 2 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
v1.4.4
- client.SetLogger accepts the `KayveeLogger` interface
v1.5.0
- PUT endpoints now support paging
33 changes: 23 additions & 10 deletions clients/go/gengo.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,14 @@ func generateIteratorTypes(s *spec.Swagger, g *swagger.Generator, paths *spec.Pa
func operationCode(s *spec.Swagger, op *spec.Operation, basePath, method, methodPath string) (string, error) {
var buf bytes.Buffer

method, err := methodCode(s, op, basePath, method, methodPath)
generatedMethodCodeString, err := methodCode(s, op, basePath, method, methodPath)
if err != nil {
return "", err
}

buf.WriteString(method)
buf.WriteString(generatedMethodCodeString)
if _, hasPaging := swagger.PagingParam(op); hasPaging {
iter, err := iterCode(s, op, basePath, methodPath)
iter, err := iterCode(s, op, basePath, methodPath, method)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -414,10 +414,7 @@ func buildPathCode(s *spec.Swagger, op *spec.Operation, basePath, methodPath str
return buf.String()
}

// buildRequestCode adds the body and makes the request
func buildRequestCode(s *spec.Swagger, op *spec.Operation, method string) string {
var buf bytes.Buffer

func buildBodyCode(s *spec.Swagger, op *spec.Operation, method string) string {
for _, param := range op.Parameters {
if param.In == "body" {
t := swagger.ParamToTemplate(&param, op)
Expand All @@ -432,9 +429,16 @@ func buildRequestCode(s *spec.Swagger, op *spec.Operation, method string) string
if err != nil {
panic(fmt.Errorf("unexpected error: %s", err))
}
buf.WriteString(str)
return str
}
}
return ""
}

// buildRequestCode adds the body and makes the request
func buildRequestCode(s *spec.Swagger, op *spec.Operation, method string) string {
var buf bytes.Buffer
buf.WriteString(buildBodyCode(s, op, method))

buf.WriteString(fmt.Sprintf(`
req, err := http.NewRequest("%s", path, bytes.NewBuffer(body))
Expand Down Expand Up @@ -633,7 +637,7 @@ var codeDetectorTmplStr = `
{{end}}
`

func iterCode(s *spec.Swagger, op *spec.Operation, basePath, methodPath string) (string, error) {
func iterCode(s *spec.Swagger, op *spec.Operation, basePath, methodPath, method string) (string, error) {
capOpID := swagger.Capitalize(op.ID)
resourceType, needsPointer, err := swagger.PagingResourceType(s, op)
if err != nil {
Expand All @@ -660,6 +664,8 @@ func iterCode(s *spec.Swagger, op *spec.Operation, basePath, methodPath string)
Input: swagger.OperationInput(op),
BuildPathCode: buildPathCode(s, op, basePath, methodPath),
BuildHeadersCode: buildHeadersCode(s, op),
BuildBodyCode: buildBodyCode(s, op, method),
Method: method,
ResponseType: responseType,
ResourceType: resourceType,
ResponseAccessString: resourceAccessString,
Expand All @@ -674,6 +680,8 @@ type iterTmpl struct {
Input string
BuildPathCode string
BuildHeadersCode string
BuildBodyCode string
Method string
ResponseType string
ResourceType string
ResponseAccessString string
Expand All @@ -689,6 +697,7 @@ type {{.OpID}}IterImpl struct {
err error
nextURL string
headers map[string]string
body []byte
}
// New{{.OpID}}Iter constructs an iterator that makes calls to {{.OpID}} for
Expand All @@ -699,17 +708,21 @@ func (c *WagClient) New{{.CapOpID}}Iter(ctx context.Context, {{.Input}}) ({{.Cap
headers := make(map[string]string)
{{.BuildHeadersCode}}
var body []byte
{{.BuildBodyCode}}
return &{{.OpID}}IterImpl{
c: c,
ctx: ctx,
lastResponse: {{.ResponseType}}{},
nextURL: path,
headers: headers,
body: body,
}, nil
}
func (i *{{.OpID}}IterImpl) refresh() error {
req, err := http.NewRequest("GET", i.nextURL, nil)
req, err := http.NewRequest("{{.Method}}", i.nextURL, bytes.NewBuffer(i.body))
if err != nil {
i.err = err
Expand Down
8 changes: 4 additions & 4 deletions hardcoded/hardcoded.go

Large diffs are not rendered by default.

202 changes: 200 additions & 2 deletions samples/gen-go/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ type getAuthorsIterImpl struct {
err error
nextURL string
headers map[string]string
body []byte
}

// NewgetAuthorsIter constructs an iterator that makes calls to getAuthors for
Expand All @@ -185,17 +186,20 @@ func (c *WagClient) NewGetAuthorsIter(ctx context.Context, i *models.GetAuthorsI

headers := make(map[string]string)

var body []byte

return &getAuthorsIterImpl{
c: c,
ctx: ctx,
lastResponse: []*models.Author{},
nextURL: path,
headers: headers,
body: body,
}, nil
}

func (i *getAuthorsIterImpl) refresh() error {
req, err := http.NewRequest("GET", i.nextURL, nil)
req, err := http.NewRequest("GET", i.nextURL, bytes.NewBuffer(i.body))

if err != nil {
i.err = err
Expand Down Expand Up @@ -298,6 +302,196 @@ func (c *WagClient) doGetAuthorsRequest(ctx context.Context, req *http.Request,
}
}

// GetAuthorsWithPut makes a PUT request to /authors
// Gets authors, but needs to use the body so it's a PUT
// 200: *models.AuthorsResponse
// 400: *models.BadRequest
// 500: *models.InternalError
// default: client side HTTP errors, for example: context.DeadlineExceeded.
func (c *WagClient) GetAuthorsWithPut(ctx context.Context, i *models.GetAuthorsWithPutInput) (*models.AuthorsResponse, error) {
headers := make(map[string]string)

var body []byte
path, err := i.Path()

if err != nil {
return nil, err
}

path = c.basePath + path

if i.FavoriteBooks != nil {

var err error
body, err = json.Marshal(i.FavoriteBooks)

if err != nil {
return nil, err
}

}

req, err := http.NewRequest("PUT", path, bytes.NewBuffer(body))

if err != nil {
return nil, err
}

resp, _, err := c.doGetAuthorsWithPutRequest(ctx, req, headers)
return resp, err
}

type getAuthorsWithPutIterImpl struct {
c *WagClient
ctx context.Context
lastResponse []*models.Author
index int
err error
nextURL string
headers map[string]string
body []byte
}

// NewgetAuthorsWithPutIter constructs an iterator that makes calls to getAuthorsWithPut for
// each page.
func (c *WagClient) NewGetAuthorsWithPutIter(ctx context.Context, i *models.GetAuthorsWithPutInput) (GetAuthorsWithPutIter, error) {
path, err := i.Path()

if err != nil {
return nil, err
}

path = c.basePath + path

headers := make(map[string]string)

var body []byte

if i.FavoriteBooks != nil {

var err error
body, err = json.Marshal(i.FavoriteBooks)

if err != nil {
return nil, err
}

}

return &getAuthorsWithPutIterImpl{
c: c,
ctx: ctx,
lastResponse: []*models.Author{},
nextURL: path,
headers: headers,
body: body,
}, nil
}

func (i *getAuthorsWithPutIterImpl) refresh() error {
req, err := http.NewRequest("PUT", i.nextURL, bytes.NewBuffer(i.body))

if err != nil {
i.err = err
return err
}

resp, nextPage, err := i.c.doGetAuthorsWithPutRequest(i.ctx, req, i.headers)
if err != nil {
i.err = err
return err
}

i.lastResponse = resp.AuthorSet.Results
i.index = 0
if nextPage != "" {
i.nextURL = i.c.basePath + nextPage
} else {
i.nextURL = ""
}
return nil
}

// Next retrieves the next resource from the iterator and assigns it to the
// provided pointer, fetching a new page if necessary. Returns true if it
// successfully retrieves a new resource.
func (i *getAuthorsWithPutIterImpl) Next(v *models.Author) bool {
if i.err != nil {
return false
} else if i.index < len(i.lastResponse) {
*v = *i.lastResponse[i.index]
i.index++
return true
} else if i.nextURL == "" {
return false
}

if err := i.refresh(); err != nil {
return false
}
return i.Next(v)
}

// Err returns an error if one occurred when .Next was called.
func (i *getAuthorsWithPutIterImpl) Err() error {
return i.err
}

func (c *WagClient) doGetAuthorsWithPutRequest(ctx context.Context, req *http.Request, headers map[string]string) (*models.AuthorsResponse, string, error) {
client := &http.Client{Transport: c.transport}

for field, value := range headers {
req.Header.Set(field, value)
}

// Add the opname for doers like tracing
ctx = context.WithValue(ctx, opNameCtx{}, "getAuthorsWithPut")
req = req.WithContext(ctx)
// Don't add the timeout in a "doer" because we don't want to call "defer.cancel()"
// until we've finished all the processing of the request object. Otherwise we'll cancel
// our own request before we've finished it.
if c.defaultTimeout != 0 {
ctx, cancel := context.WithTimeout(req.Context(), c.defaultTimeout)
defer cancel()
req = req.WithContext(ctx)
}
resp, err := c.requestDoer.Do(client, req)
if err != nil {
return nil, "", err
}
defer resp.Body.Close()
switch resp.StatusCode {

case 200:

var output models.AuthorsResponse
if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
return nil, "", err
}

return &output, resp.Header.Get("X-Next-Page-Path"), nil

case 400:

var output models.BadRequest
if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
return nil, "", err
}
return nil, "", &output

case 500:

var output models.InternalError
if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
return nil, "", err
}
return nil, "", &output

default:
return nil, "", &models.InternalError{Message: "Unknown response"}
}
}

// GetBooks makes a GET request to /books
// Returns a list of books
// 200: []models.Book
Expand Down Expand Up @@ -336,6 +530,7 @@ type getBooksIterImpl struct {
err error
nextURL string
headers map[string]string
body []byte
}

// NewgetBooksIter constructs an iterator that makes calls to getBooks for
Expand All @@ -353,17 +548,20 @@ func (c *WagClient) NewGetBooksIter(ctx context.Context, i *models.GetBooksInput

headers["authorization"] = i.Authorization

var body []byte

return &getBooksIterImpl{
c: c,
ctx: ctx,
lastResponse: []models.Book{},
nextURL: path,
headers: headers,
body: body,
}, nil
}

func (i *getBooksIterImpl) refresh() error {
req, err := http.NewRequest("GET", i.nextURL, nil)
req, err := http.NewRequest("GET", i.nextURL, bytes.NewBuffer(i.body))

if err != nil {
i.err = err
Expand Down
16 changes: 16 additions & 0 deletions samples/gen-go/client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ type Client interface {

NewGetAuthorsIter(ctx context.Context, i *models.GetAuthorsInput) (GetAuthorsIter, error)

// GetAuthorsWithPut makes a PUT request to /authors
// Gets authors, but needs to use the body so it's a PUT
// 200: *models.AuthorsResponse
// 400: *models.BadRequest
// 500: *models.InternalError
// default: client side HTTP errors, for example: context.DeadlineExceeded.
GetAuthorsWithPut(ctx context.Context, i *models.GetAuthorsWithPutInput) (*models.AuthorsResponse, error)

NewGetAuthorsWithPutIter(ctx context.Context, i *models.GetAuthorsWithPutInput) (GetAuthorsWithPutIter, error)

// GetBooks makes a GET request to /books
// Returns a list of books
// 200: []models.Book
Expand Down Expand Up @@ -81,6 +91,12 @@ type GetAuthorsIter interface {
Err() error
}

// GetAuthorsWithPutIter defines the methods available on GetAuthorsWithPut iterators.
type GetAuthorsWithPutIter interface {
Next(*models.Author) bool
Err() error
}

// GetBooksIter defines the methods available on GetBooks iterators.
type GetBooksIter interface {
Next(*models.Book) bool
Expand Down
Loading

0 comments on commit b33fe8d

Please sign in to comment.