Closed ctreatma closed 1 year ago
@displague @ctreatma I have tried to implement pagination with the mustache templates of openapi generator today. there are several issues:
Mustache is logic-less, so it's hard to implement the condition of when the paginated-list function should be emitted by the generator. There's nothing like if parameters[].name == "page"
. the furthest I got was to iterate through query params of a get-request operation, but even then I wasn't able to condition properly. It seems it's by design:
https://stackoverflow.com/questions/20345288/check-with-mustache-js-if-parameter-is-a-specific-value
Then, I was thinking I would add a boolean attribute isPaginated
to ['paths'][/project/{id}/devices][get]
in the spec. That would allow to distinguish in the mustache templates, but it makes the spec not valid.
This was my template that would generate files like api_device_paginated_lister.go
.
templates/api_paginated_lister.mustache
:
{{>partial_header}}
package {{packageName}}
{{#operations}}
import (
"bytes"
"context"
"io"
"net/http"
"net/url"
{{#imports}} "{{import}}"
{{/imports}}
)
{{#operation}}
{{isPaginated}}
// The code is just a placeholder, I wanted to know if it's emitted only on paginated methods
func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}{{^structPrefix}}Api{{/structPrefix}}{{operationId}}Request) ({{#returnType}}{{^isArray}}{{^returnTypeIsPrimitive}}{{^isResponseFile}}*{{/isResponseFile}}{{/returnTypeIsPrimitive}}{{/isArray}}{{{.}}}, {{/returnType}}*http.Response, error) {
var items []{{returnType}}
pageNumber := int32(1)
// classname {{classname}}, {{&classname}}
for {
page, _, err := r.Page(pageNumber).Execute()
if err != nil {
return nil, err
}
items = append(items, page.Devices...)
if page.Meta.GetLastPage() <= page.Meta.GetCurrentPage() {
break
}
}
return items, nil
}
{{/isPaginated}}
{{/operation}}
{{/operations}}
To consider the templates, we must have config.yaml
as
templateDir: /local/templates
files:
api_paginated_lister.mustache:
templateType: API
destinationFilename: _paginated_lister.go
.. and -c config.yaml
to the openapi-cli call.
I also tried to come up with an yq
expression that would add a boolean flag isPaginated
to ["paths"]["/projects{id}/devices"]["get"]
. I came up with
yq 'with(.paths[].get | select(.parameters[].name == "page"); .isPaginated=true)' < $1 > $2
.. but it's not completely correct.
@t0mk The Path syntax is well defined, you can't add arbitrary fields unless they follow the x-
format.
@t0mk page.Devices
would also need to be template-ified in your example. I don't presume determining the proper plural is trivial.
@displague Thanks for the tip on the x-
properties, it couldn't a fix for my problem.
https://swagger.io/specification/#paths-object
As for the the plural, I think it can be worked out from the template variables. It might not be gramtatically correct, but I don't think it will conflict.
Closing in favor of #150, which will generate the changes in this PR for all paginated endpoints using a combination of vendor extensions and custom templates.
This serves as an example of how we could implement automatic page navigation, similar to what was done in
packngo
.Relates to #131