Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: appengine/ephelper/epfrontend/discovery.go

Issue 1750143003: Remove ephelper and other endpoints code. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/ephelper/context.go ('k') | appengine/ephelper/epfrontend/discovery_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package epfrontend
6
7 import (
8 "fmt"
9 "net/http"
10 "net/url"
11 "regexp"
12 "sort"
13 "strings"
14
15 "github.com/GoogleCloudPlatform/go-endpoints/endpoints"
16 )
17
18 var (
19 // Capture {stuff}.
20 reParam = regexp.MustCompile(`\{([^\}]+)\}`)
21 )
22
23 func getHostURL(r *http.Request) *url.URL {
24 u := url.URL{
25 Scheme: "http",
26 Host: r.Host,
27 }
28 if r.TLS != nil {
29 u.Scheme = "https"
30 }
31 return &u
32 }
33
34 func (s *Server) handleDirectoryList(r *http.Request) (interface{}, error) {
35 u := getHostURL(r)
36 u.Path = r.URL.Path
37 return s.directoryList(u), nil
38 }
39
40 // directoryList converts a list of backend APIs into an API directory.
41 //
42 // The conversion isn't perfect or spec-confirming. It makes a set of minimal
43 // mutations to be compatible with the `google-api-go-generator` tool.
44 //
45 // Each directory item's DiscoveryLink is generated from the item's index.
46 // For example, directory item #0 is hosted at "./apis/0/rest".
47 func (s *Server) directoryList(root *url.URL) *directoryList {
48 serviceNames := make([]string, 0, len(s.services))
49 for k := range s.services {
50 serviceNames = append(serviceNames, k)
51 }
52 sort.Strings(serviceNames)
53
54 d := directoryList{
55 Kind: "discovery#directoryList",
56 DiscoveryVersion: "v1",
57 Items: make([]*directoryItem, len(serviceNames)),
58 }
59
60 for i, name := range serviceNames {
61 api := s.services[name]
62 di := directoryItem{
63 Kind: "discovery#directoryItem",
64 ID: apiID(api),
65 Name: api.Name,
66 Version: api.Version,
67 Description: api.Desc,
68 DiscoveryRestURL: safeURLPathJoin(root.String(), api.Nam e, api.Version, "rest"),
69 DiscoveryLink: safeURLPathJoin(".", "apis", api.Name, api.Version, "rest"),
70 RootURL: root.String(),
71 Preferred: false,
72 }
73 d.Items[i] = &di
74 }
75
76 return &d
77 }
78
79 func apiID(a *endpoints.APIDescriptor) string {
80 return fmt.Sprintf("%s:%s", a.Name, a.Version)
81 }
82
83 func (s *Server) handleRestDescription(r *http.Request, a *endpoints.APIDescript or) (interface{}, error) {
84 u := getHostURL(r)
85 u.Path = s.root
86 d, err := buildRestDescription(u, a)
87 return d, err
88 }
89
90 // buildRestDescription returns a single directory item's REST description
91 // structure.
92 //
93 // This is a JSON-compatible element that describes the APIs exported by a
94 // singleAPI.
95 func buildRestDescription(root *url.URL, a *endpoints.APIDescriptor) (*restDescr iption, error) {
96 servicePath := safeURLPathJoin(a.Name, a.Version)
97 rdesc := restDescription{
98 Kind: "discovery#restDescription",
99 DiscoveryVersion: "v1",
100
101 Protocol: "rest",
102 ID: apiID(a),
103 Name: a.Name,
104 Version: a.Version,
105 Description: a.Desc,
106 RootURL: root.String(),
107 BasePath: safeURLPathJoin("", root.Path, servicePath, ""),
108 BaseURL: safeURLPathJoin(root.String(), servicePath, ""),
109 ServicePath: safeURLPathJoin(servicePath, ""),
110 DefaultVersion: a.Default,
111 }
112 if len(a.Descriptor.Schemas) > 0 {
113 rdesc.Schemas = make(map[string]*endpoints.APISchemaDescriptor, len(a.Descriptor.Schemas))
114 }
115 if len(a.Methods) > 0 {
116 rdesc.Methods = make(map[string]*restMethod, len(a.Methods))
117 }
118
119 for name, schema := range a.Descriptor.Schemas {
120 schema := *schema
121 rdesc.Schemas[name] = &schema
122 }
123
124 for id, desc := range a.Methods {
125 m := restMethod{
126 ID: id,
127 Path: desc.Path,
128 HTTPMethod: desc.HTTPMethod,
129 Scopes: desc.Scopes,
130 Description: desc.Desc,
131 }
132 m.ParameterOrder = parseParameterOrderFromPath(m.Path)
133 if nParams := len(desc.Request.Params) + len(desc.Response.Param s); nParams > 0 {
134 m.Parameters = make(map[string]*restMethodParameter, nPa rams)
135 }
136
137 err := error(nil)
138 rosyMethod := a.Descriptor.Methods[desc.RosyMethod]
139 if rosyMethod == nil {
140 return nil, fmt.Errorf("no descriptor for RosyMethod %q" , desc.RosyMethod)
141 }
142 m.Request, err = m.buildMethodParamRef(&desc.Request, rosyMethod .Request, true)
143 if err != nil {
144 return nil, fmt.Errorf("failed to build method [%s] requ est: %s", m.ID, err)
145 }
146
147 m.Response, err = m.buildMethodParamRef(&desc.Response, rosyMeth od.Response, false)
148 if err != nil {
149 return nil, fmt.Errorf("failed to build method [%s] resp onse: %s", m.ID, err)
150 }
151
152 rdesc.Methods[strings.TrimPrefix(m.ID, fmt.Sprintf("%s.", a.Name ))] = &m
153 }
154
155 return &rdesc, nil
156 }
157
158 func (m *restMethod) buildMethodParamRef(desc *endpoints.APIReqRespDescriptor, r ef *endpoints.APISchemaRef, canPath bool) (
159 *restMethodParameterRef, error) {
160 pathParams := map[string]struct{}{}
161 if canPath {
162 for _, p := range m.ParameterOrder {
163 pathParams[p] = struct{}{}
164 }
165 }
166
167 for name, param := range desc.Params {
168 rmp := restMethodParameter{
169 Required: param.Required, // All path parameters are req uired.
170 }
171 rmp.Type, rmp.Format = convertBackendType(param.Type)
172 _, inPath := pathParams[name]
173
174 if m.HTTPMethod == "GET" && !inPath {
175 rmp.Location = "query"
176 } else {
177 rmp.Location = "path"
178 rmp.Required = true
179 }
180 m.Parameters[name] = &rmp
181 }
182
183 if desc.Body == "empty" {
184 return nil, nil
185 }
186
187 paramRef := restMethodParameterRef{
188 ParameterName: desc.BodyName,
189 }
190 if ref != nil {
191 paramRef.Ref = ref.Ref
192 }
193
194 return &paramRef, nil
195 }
196
197 func convertBackendType(t string) (string, string) {
198 switch t {
199 case "int32":
200 return "integer", "int32"
201 case "int64":
202 return "string", "int64"
203 case "uint32":
204 return "integer", "uint32"
205 case "uint64":
206 return "string", "uint64"
207 case "float":
208 return "number", "float"
209 case "double":
210 return "number", "double"
211 case "boolean":
212 return "boolean", ""
213 case "string":
214 return "string", ""
215 }
216
217 return "", ""
218 }
219
220 func parseParameterOrderFromPath(path string) []string {
221 matches := reParam.FindAllStringSubmatch(path, -1)
222 if len(matches) == 0 {
223 return nil
224 }
225
226 po := make([]string, 0, len(matches))
227 for _, match := range matches {
228 po = append(po, match[1])
229 }
230 return po
231 }
232
233 // directoryList is a Google Cloud Endpoints frontend directory list structure.
234 //
235 // This is the first-level directory structure, which exports a series of API
236 // items.
237 type directoryList struct {
238 Kind string `json:"kind,omitempty"`
239 DiscoveryVersion string `json:"discoveryVersion,omitempty"`
240 Items []*directoryItem `json:"items,omitempty"`
241 }
242
243 // directoryItem is a single API's directoryList entry.
244 //
245 // This is a This is the second-level directory structure which exports a single
246 // API's methods.
247 //
248 // The directoryItem exports a REST API (restDescription) at its relative
249 // DiscoveryLink.
250 type directoryItem struct {
251 Kind string `json:"kind,omitempty"`
252 ID string `json:"id,omitempty"`
253 Name string `json:"name,omitempty"`
254 Version string `json:"version,omitempty"`
255 Title string `json:"title,omitempty"`
256 Description string `json:"description,omitempty"`
257 DiscoveryRestURL string `json:"discoveryRestUrl,omitempty"`
258 DiscoveryLink string `json:"discoveryLink,omitempty"`
259 RootURL string `json:"rootUrl,omitempty"`
260 Preferred bool `json:"preferred,omitempty"`
261 }
262
263 // restDescription is a hosted JSON at a rest endpoint. It is translated from a
264 // singleAPI into a form served by the frontend.
265 type restDescription struct {
266 Kind string `json:"kind,omitempty"`
267 DiscoveryVersion string `json:"discoveryVersion,omitempty"`
268
269 Protocol string `json:"protocol,omitempty"`
270 ID string `json:"id,omitempty"`
271 Name string `json:"name,omitempty"`
272 Version string `json:"version,omitempty"`
273 Description string `json:"description,omitempty"`
274 BaseURL string `json:"baseUrl,omitempty"`
275 BasePath string `json:"basePath,omitempty"`
276 RootURL string `json:"rootUrl,omitempty"`
277 ServicePath string `json:"servicePath,omitempty"`
278 Root string `json:"root,omitempty"`
279 DefaultVersion bool `json:"defaultVersion,omitempty"`
280
281 Schemas map[string]*endpoints.APISchemaDescriptor `json:"schemas,omitemp ty"`
282 Methods map[string]*restMethod `json:"methods,omitemp ty"`
283 }
284
285 type restMethod struct {
286 ID string `json:"id,omitempty"`
287 Path string `json:"path,omitempty"`
288 HTTPMethod string `json:"httpMethod,omitemp ty"`
289 Description string `json:"description,omitem pty"`
290 Parameters map[string]*restMethodParameter `json:"parameters,omitemp ty"`
291 ParameterOrder []string `json:"parameterOrder,omi tempty"`
292 Request *restMethodParameterRef `json:"request,omitempty" `
293 Response *restMethodParameterRef `json:"response,omitempty "`
294 Scopes []string `json:"scopes,omitempty"`
295 }
296
297 type restMethodParameter struct {
298 Type string `json:"type,omitempty"`
299 Format string `json:"format,omitempty"`
300 Location string `json:"location,omitempty"`
301 Required bool `json:"required,omitempty"`
302 }
303
304 type restMethodParameterRef struct {
305 Ref string `json:"$ref,omitempty"`
306 ParameterName string `json:"parameterName,omitempty"`
307 }
OLDNEW
« no previous file with comments | « appengine/ephelper/context.go ('k') | appengine/ephelper/epfrontend/discovery_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698