forked from danielgtaylor/huma
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgraphql_paginator.go
77 lines (68 loc) · 2.63 KB
/
graphql_paginator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package huma
import (
"net/url"
"strings"
link "github.com/tent/http-link-go"
)
// GraphQLPaginator defines how to to turn list responses from the HTTP API to
// GraphQL response objects.
type GraphQLPaginator interface {
// Load the paginated response from the given headers and body. After this
// call completes, your struct instance should be ready to send back to
// the client.
Load(headers map[string]string, body []interface{}) error
}
// GraphQLHeaders is a placeholder to be used in `GraphQLPaginator` struct
// implementations which gets replaced with a struct of response headers.
type GraphQLHeaders map[string]string
// GraphQLItems is a placeholder to be used in `GraphQLPaginator` struct
// implementations which gets replaced with a list of the response items model.
type GraphQLItems []interface{}
// GraphQLPaginationParams provides params for link relationships so that
// new GraphQL queries to get e.g. the next page of items are easy to construct.
type GraphQLPaginationParams struct {
First map[string]string `json:"first" doc:"First page link relationship"`
Next map[string]string `json:"next" doc:"Next page link relationship"`
Prev map[string]string `json:"prev" doc:"Previous page link relationship"`
Last map[string]string `json:"last" doc:"Last page link relationship"`
}
// GraphQLDefaultPaginator provides a default generic paginator implementation
// that makes no assumptions about pagination parameter names, headers, etc.
// It enables clients to access the response items (edges) as well as any
// response headers. If a link relation header is found in the response, then
// link relationships are parsed and turned into easy-to-use parameters for
// subsequent requests.
type GraphQLDefaultPaginator struct {
Headers GraphQLHeaders `json:"headers"`
Links GraphQLPaginationParams `json:"links" doc:"Pagination link parameters"`
Edges GraphQLItems `json:"edges"`
}
// Load the paginated response and parse link relationships if available.
func (g *GraphQLDefaultPaginator) Load(headers map[string]string, body []interface{}) error {
g.Headers = headers
if parsed, err := link.Parse(headers["link"]); err == nil && len(parsed) > 0 {
for _, item := range parsed {
parsed, err := url.Parse(item.URI)
if err != nil {
continue
}
params := map[string]string{}
query := parsed.Query()
for k := range query {
params[k] = query.Get(k)
}
switch strings.ToLower(item.Rel) {
case "first":
g.Links.First = params
case "next":
g.Links.Next = params
case "prev":
g.Links.Prev = params
case "last":
g.Links.Last = params
}
}
}
g.Edges = body
return nil
}