haveapi-go-client 0.27.3 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/haveapi-go-client.gemspec +1 -1
- data/lib/haveapi/go_client/action.rb +7 -3
- data/lib/haveapi/go_client/erb_template.rb +3 -0
- data/lib/haveapi/go_client/generator.rb +5 -2
- data/lib/haveapi/go_client/resource.rb +7 -2
- data/lib/haveapi/go_client/utils.rb +101 -1
- data/lib/haveapi/go_client/version.rb +1 -1
- data/spec/integration/generator_spec.rb +654 -2
- data/template/action.go.erb +74 -73
- data/template/authentication/oauth2.go.erb +20 -8
- data/template/authentication/token.go.erb +10 -10
- data/template/client.go.erb +41 -2
- data/template/request.go.erb +106 -8
- data/template/resource.go.erb +3 -3
- metadata +3 -4
- data/shell.nix +0 -23
data/template/action.go.erb
CHANGED
|
@@ -2,11 +2,12 @@ package <%= package %>
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
<% if action.has_path_params? -%>
|
|
5
|
+
"net/url"
|
|
5
6
|
"strings"
|
|
6
7
|
<% end -%>
|
|
7
8
|
)
|
|
8
9
|
|
|
9
|
-
// <%= action.go_type %> is a type for action <%= action.full_dot_name %>
|
|
10
|
+
// <%= action.go_type %> is a type for action <%= go_comment_text(action.full_dot_name) %>
|
|
10
11
|
type <%= action.go_type %> struct {
|
|
11
12
|
// Pointer to client
|
|
12
13
|
Client *Client
|
|
@@ -22,7 +23,7 @@ func New<%= action.go_type %>(client *Client) *<%= action.go_type %> {
|
|
|
22
23
|
// <%= action.metadata.global.input.go_type %> is a type for action global meta input parameters
|
|
23
24
|
type <%= action.metadata.global.input.go_type %> struct {
|
|
24
25
|
<% action.metadata.global.input.parameters.each do |p| -%>
|
|
25
|
-
<%= p.go_name %> <%= p.go_in_type %>
|
|
26
|
+
<%= p.go_name %> <%= p.go_in_type %> <%= go_json_tag(p.name) %>
|
|
26
27
|
<% end -%>
|
|
27
28
|
// Only selected parameters are sent to the API. Ignored if empty.
|
|
28
29
|
_selectedParameters map[string]interface{}
|
|
@@ -42,7 +43,7 @@ func (in *<%= action.metadata.global.input.go_type %>) Set<%= p.go_name %>(value
|
|
|
42
43
|
<% if p.nillable? -%>
|
|
43
44
|
in.Set<%= p.go_name %>Nil(false)
|
|
44
45
|
<% end -%>
|
|
45
|
-
in._selectedParameters[
|
|
46
|
+
in._selectedParameters[<%= go_string_literal(p.go_name) %>] = nil
|
|
46
47
|
return in
|
|
47
48
|
}
|
|
48
49
|
<% if p.nillable? -%>
|
|
@@ -57,10 +58,10 @@ func (in *<%= action.metadata.global.input.go_type %>) Set<%= p.go_name %>Nil(se
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
if set {
|
|
60
|
-
in._nilParameters[
|
|
61
|
-
in.SelectParameters(
|
|
61
|
+
in._nilParameters[<%= go_string_literal(p.go_name) %>] = nil
|
|
62
|
+
in.SelectParameters(<%= go_string_literal(p.go_name) %>)
|
|
62
63
|
} else {
|
|
63
|
-
delete(in._nilParameters,
|
|
64
|
+
delete(in._nilParameters, <%= go_string_literal(p.go_name) %>)
|
|
64
65
|
}
|
|
65
66
|
return in
|
|
66
67
|
}
|
|
@@ -95,7 +96,7 @@ func (in *<%= action.metadata.global.input.go_type %>) AnySelected() bool {
|
|
|
95
96
|
// <%= action.input.go_type %> is a type for action input parameters
|
|
96
97
|
type <%= action.input.go_type %> struct {
|
|
97
98
|
<% action.input.parameters.each do |p| -%>
|
|
98
|
-
<%= p.go_name %> <%= p.go_in_type %>
|
|
99
|
+
<%= p.go_name %> <%= p.go_in_type %> <%= go_json_tag(p.name) %>
|
|
99
100
|
<% end -%>
|
|
100
101
|
// Only selected parameters are sent to the API. Ignored if empty.
|
|
101
102
|
_selectedParameters map[string]interface{}
|
|
@@ -115,7 +116,7 @@ func (in *<%= action.input.go_type %>) Set<%= p.go_name %>(value <%= p.go_in_typ
|
|
|
115
116
|
<% if p.nillable? -%>
|
|
116
117
|
in.Set<%= p.go_name %>Nil(false)
|
|
117
118
|
<% end -%>
|
|
118
|
-
in._selectedParameters[
|
|
119
|
+
in._selectedParameters[<%= go_string_literal(p.go_name) %>] = nil
|
|
119
120
|
return in
|
|
120
121
|
}
|
|
121
122
|
<% if p.nillable? -%>
|
|
@@ -130,10 +131,10 @@ func (in *<%= action.input.go_type %>) Set<%= p.go_name %>Nil(set bool) *<%= act
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
if set {
|
|
133
|
-
in._nilParameters[
|
|
134
|
-
in.SelectParameters(
|
|
134
|
+
in._nilParameters[<%= go_string_literal(p.go_name) %>] = nil
|
|
135
|
+
in.SelectParameters(<%= go_string_literal(p.go_name) %>)
|
|
135
136
|
} else {
|
|
136
|
-
delete(in._nilParameters,
|
|
137
|
+
delete(in._nilParameters, <%= go_string_literal(p.go_name) %>)
|
|
137
138
|
}
|
|
138
139
|
return in
|
|
139
140
|
}
|
|
@@ -183,10 +184,10 @@ func (in *<%= action.input.go_type %>) AnySelected() bool {
|
|
|
183
184
|
// <%= action.go_request_type %> is a type for the entire action request
|
|
184
185
|
type <%= action.go_request_type %> struct {
|
|
185
186
|
<% if action.has_input? -%>
|
|
186
|
-
<%= action.input.go_namespace %> map[string]interface{}
|
|
187
|
+
<%= action.input.go_namespace %> map[string]interface{} <%= go_json_tag(action.input.namespace) %>
|
|
187
188
|
<% end -%>
|
|
188
189
|
<% if action.metadata.has_global_input? -%>
|
|
189
|
-
Meta map[string]interface{}
|
|
190
|
+
Meta map[string]interface{} <%= go_json_tag(action.resource.api_version.metadata_namespace) %>
|
|
190
191
|
<% end -%>
|
|
191
192
|
}
|
|
192
193
|
<% end -%>
|
|
@@ -196,9 +197,9 @@ type <%= action.go_request_type %> struct {
|
|
|
196
197
|
type <%= action.output.go_type %> struct {
|
|
197
198
|
<% action.output.parameters.each do |p| -%>
|
|
198
199
|
<% if p.respond_to?(:association) -%>
|
|
199
|
-
<%= p.go_name %> *<%= p.go_out_type %>
|
|
200
|
+
<%= p.go_name %> *<%= p.go_out_type %> <%= go_json_tag(p.name) %>
|
|
200
201
|
<% else -%>
|
|
201
|
-
<%= p.go_name %> <%= p.go_out_type %>
|
|
202
|
+
<%= p.go_name %> <%= p.go_out_type %> <%= go_json_tag(p.name) %>
|
|
202
203
|
<% end -%>
|
|
203
204
|
<% end -%>
|
|
204
205
|
}
|
|
@@ -208,23 +209,23 @@ type <%= action.output.go_type %> struct {
|
|
|
208
209
|
// <%= action.metadata.global.output.go_type %> is a type for global output metadata parameters
|
|
209
210
|
type <%= action.metadata.global.output.go_type %> struct {
|
|
210
211
|
<% action.metadata.global.output.parameters.each do |p| -%>
|
|
211
|
-
<%= p.go_name %> <%= p.go_out_type %>
|
|
212
|
+
<%= p.go_name %> <%= p.go_out_type %> <%= go_json_tag(p.name) %>
|
|
212
213
|
<% end -%>
|
|
213
214
|
}
|
|
214
215
|
<% end -%>
|
|
215
216
|
|
|
216
217
|
// Type for action response, including envelope
|
|
217
218
|
type <%= action.go_response_type %> struct {
|
|
218
|
-
Action *<%= action.go_type %>
|
|
219
|
+
Action *<%= action.go_type %> <%= go_json_tag('-') %>
|
|
219
220
|
*Envelope
|
|
220
221
|
<% if action.has_output? -%>
|
|
221
222
|
<% if %w(hash object).include?(action.output.layout) -%>
|
|
222
223
|
// Action output encapsulated within a namespace
|
|
223
224
|
Response *struct {
|
|
224
|
-
<%= action.output.go_namespace %> *<%= action.output.go_type %>
|
|
225
|
+
<%= action.output.go_namespace %> *<%= action.output.go_type %> <%= go_json_tag(action.output.namespace) %>
|
|
225
226
|
<% if action.blocking? -%>
|
|
226
227
|
// Global output metadata
|
|
227
|
-
Meta *<%= action.metadata.global.output.go_type %>
|
|
228
|
+
Meta *<%= action.metadata.global.output.go_type %> <%= go_json_tag(action.resource.api_version.metadata_namespace) %>
|
|
228
229
|
<% end -%>
|
|
229
230
|
}
|
|
230
231
|
|
|
@@ -233,10 +234,10 @@ type <%= action.go_response_type %> struct {
|
|
|
233
234
|
<% elsif %w(hash_list object_list).include?(action.output.layout) -%>
|
|
234
235
|
// Action output encapsulated within a namespace
|
|
235
236
|
Response *struct {
|
|
236
|
-
<%= action.output.go_namespace %> []*<%= action.output.go_type %>
|
|
237
|
+
<%= action.output.go_namespace %> []*<%= action.output.go_type %> <%= go_json_tag(action.output.namespace) %>
|
|
237
238
|
<% if action.blocking? -%>
|
|
238
239
|
// Global output metadata
|
|
239
|
-
Meta *<%= action.metadata.global.output.go_type %>
|
|
240
|
+
Meta *<%= action.metadata.global.output.go_type %> <%= go_json_tag(action.resource.api_version.metadata_namespace) %>
|
|
240
241
|
<% end -%>
|
|
241
242
|
}
|
|
242
243
|
|
|
@@ -247,7 +248,7 @@ type <%= action.go_response_type %> struct {
|
|
|
247
248
|
// Action output encapsulated within a namespace
|
|
248
249
|
Response *struct {
|
|
249
250
|
// Global output metadata
|
|
250
|
-
Meta *<%= action.metadata.global.output.go_type %>
|
|
251
|
+
Meta *<%= action.metadata.global.output.go_type %> <%= go_json_tag(action.resource.api_version.metadata_namespace) %>
|
|
251
252
|
}
|
|
252
253
|
<% end -%>
|
|
253
254
|
}
|
|
@@ -263,7 +264,7 @@ func (action *<%= action.go_type %>) Call() (*<%= action.go_response_type %>, er
|
|
|
263
264
|
func (action *<%= action.go_type %>) Prepare() *<%= action.go_invocation_type%> {
|
|
264
265
|
return &<%= action.go_invocation_type %>{
|
|
265
266
|
Action: action,
|
|
266
|
-
Path:
|
|
267
|
+
Path: <%= go_string_literal(action.path) %>,
|
|
267
268
|
}
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -292,7 +293,7 @@ func (inv *<%= action.go_invocation_type %>) SetPathParamInt(param string, value
|
|
|
292
293
|
|
|
293
294
|
// SetPathParamString sets string path parameter
|
|
294
295
|
func (inv *<%= action.go_invocation_type %>) SetPathParamString(param string, value string) *<%= action.go_invocation_type %> {
|
|
295
|
-
inv.Path = strings.Replace(inv.Path, "{"+param+"}", value, 1)
|
|
296
|
+
inv.Path = strings.Replace(inv.Path, "{"+param+"}", url.PathEscape(value), 1)
|
|
296
297
|
return inv
|
|
297
298
|
}
|
|
298
299
|
<% end -%>
|
|
@@ -371,23 +372,23 @@ func (inv *<%= action.go_invocation_type %>) validate() error {
|
|
|
371
372
|
if inv.Input != nil {
|
|
372
373
|
<% action.input.parameters.each do |p| -%>
|
|
373
374
|
<% if %w(Float Datetime Resource).include?(p.type) -%>
|
|
374
|
-
if inv.IsParameterSelected(
|
|
375
|
-
if !inv.IsParameterNil(
|
|
375
|
+
if inv.IsParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
376
|
+
if !inv.IsParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
376
377
|
<% if p.type == 'Float' -%>
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
378
|
+
if !isFiniteFloat64(inv.Input.<%= p.go_name %>) {
|
|
379
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid float")
|
|
380
|
+
}
|
|
380
381
|
<% elsif p.type == 'Datetime' -%>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
382
|
+
normalized, ok := normalizeAndCheckDatetimeString(inv.Input.<%= p.go_name %>)
|
|
383
|
+
if !ok {
|
|
384
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid datetime")
|
|
385
|
+
} else {
|
|
386
|
+
inv.Input.<%= p.go_name %> = normalized
|
|
387
|
+
}
|
|
387
388
|
<% elsif p.type == 'Resource' -%>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
if inv.Input.<%= p.go_name %> < 0 {
|
|
390
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid resource id")
|
|
391
|
+
}
|
|
391
392
|
<% end -%>
|
|
392
393
|
}
|
|
393
394
|
}
|
|
@@ -399,23 +400,23 @@ func (inv *<%= action.go_invocation_type %>) validate() error {
|
|
|
399
400
|
if inv.MetaInput != nil {
|
|
400
401
|
<% action.metadata.global.input.parameters.each do |p| -%>
|
|
401
402
|
<% if %w(Float Datetime Resource).include?(p.type) -%>
|
|
402
|
-
if inv.IsMetaParameterSelected(
|
|
403
|
-
if !inv.IsMetaParameterNil(
|
|
403
|
+
if inv.IsMetaParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
404
|
+
if !inv.IsMetaParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
404
405
|
<% if p.type == 'Float' -%>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
406
|
+
if !isFiniteFloat64(inv.MetaInput.<%= p.go_name %>) {
|
|
407
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid float")
|
|
408
|
+
}
|
|
408
409
|
<% elsif p.type == 'Datetime' -%>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
410
|
+
normalized, ok := normalizeAndCheckDatetimeString(inv.MetaInput.<%= p.go_name %>)
|
|
411
|
+
if !ok {
|
|
412
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid datetime")
|
|
413
|
+
} else {
|
|
414
|
+
inv.MetaInput.<%= p.go_name %> = normalized
|
|
415
|
+
}
|
|
415
416
|
<% elsif p.type == 'Resource' -%>
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
if inv.MetaInput.<%= p.go_name %> < 0 {
|
|
418
|
+
verr.Add(<%= go_string_literal(p.name) %>, "not a valid resource id")
|
|
419
|
+
}
|
|
419
420
|
<% end -%>
|
|
420
421
|
}
|
|
421
422
|
}
|
|
@@ -471,7 +472,7 @@ func (inv *<%= action.go_invocation_type %>) callAsBody() (*<%= action.go_respon
|
|
|
471
472
|
input := make(map[string]interface{})
|
|
472
473
|
<% end -%>
|
|
473
474
|
resp := &<%= action.go_response_type %>{Action: inv.Action}
|
|
474
|
-
err := inv.Action.Client.DoBodyRequest(
|
|
475
|
+
err := inv.Action.Client.DoBodyRequest(<%= go_string_literal(action.http_method) %>, inv.Path, input, resp)
|
|
475
476
|
<% if action.has_output? -%>
|
|
476
477
|
if err == nil && resp.Status {
|
|
477
478
|
resp.Output = resp.Response.<%= action.output.go_namespace %>
|
|
@@ -563,15 +564,15 @@ func (resp *<%= action.go_response_type %>) CancelOperation() (*ActionActionStat
|
|
|
563
564
|
func (inv *<%= action.go_invocation_type %>) convertInputToQueryParams(ret map[string]string) {
|
|
564
565
|
if inv.Input != nil {
|
|
565
566
|
<% action.input.parameters.each do |p| -%>
|
|
566
|
-
if inv.IsParameterSelected(
|
|
567
|
+
if inv.IsParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
567
568
|
<% if p.nillable? -%>
|
|
568
|
-
if inv.IsParameterNil(
|
|
569
|
-
ret[
|
|
569
|
+
if inv.IsParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
570
|
+
ret[<%= go_query_key(action.input.namespace, p.name) %>] = ""
|
|
570
571
|
} else {
|
|
571
|
-
ret[
|
|
572
|
+
ret[<%= go_query_key(action.input.namespace, p.name) %>] = <% if p.go_in_type == 'string' %>inv.Input.<%= p.go_name %><% else %>convert<%= p.go_in_type.capitalize %>ToString(inv.Input.<%= p.go_name %>)<% end %>
|
|
572
573
|
}
|
|
573
574
|
<% else -%>
|
|
574
|
-
ret[
|
|
575
|
+
ret[<%= go_query_key(action.input.namespace, p.name) %>] = <% if p.go_in_type == 'string' %>inv.Input.<%= p.go_name %><% else %>convert<%= p.go_in_type.capitalize %>ToString(inv.Input.<%= p.go_name %>)<% end %>
|
|
575
576
|
<% end -%>
|
|
576
577
|
}
|
|
577
578
|
<% end -%>
|
|
@@ -583,15 +584,15 @@ func (inv *<%= action.go_invocation_type %>) convertInputToQueryParams(ret map[s
|
|
|
583
584
|
func (inv *<%= action.go_invocation_type %>) convertMetaInputToQueryParams(ret map[string]string) {
|
|
584
585
|
if inv.MetaInput != nil {
|
|
585
586
|
<% action.metadata.global.input.parameters.each do |p| -%>
|
|
586
|
-
if inv.IsMetaParameterSelected(
|
|
587
|
+
if inv.IsMetaParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
587
588
|
<% if p.nillable? -%>
|
|
588
|
-
if inv.IsMetaParameterNil(
|
|
589
|
-
ret[
|
|
589
|
+
if inv.IsMetaParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
590
|
+
ret[<%= go_query_key(action.resource.api_version.metadata_namespace, p.name) %>] = ""
|
|
590
591
|
} else {
|
|
591
|
-
ret[
|
|
592
|
+
ret[<%= go_query_key(action.resource.api_version.metadata_namespace, p.name) %>] = <% if p.go_in_type == 'string' %>inv.MetaInput.<%= p.go_name %><% else %>convert<%= p.go_in_type.capitalize %>ToString(inv.MetaInput.<%= p.go_name %>)<% end %>
|
|
592
593
|
}
|
|
593
594
|
<% else -%>
|
|
594
|
-
ret[
|
|
595
|
+
ret[<%= go_query_key(action.resource.api_version.metadata_namespace, p.name) %>] = <% if p.go_in_type == 'string' %>inv.MetaInput.<%= p.go_name %><% else %>convert<%= p.go_in_type.capitalize %>ToString(inv.MetaInput.<%= p.go_name %>)<% end %>
|
|
595
596
|
<% end -%>
|
|
596
597
|
}
|
|
597
598
|
<% end -%>
|
|
@@ -617,15 +618,15 @@ func (inv *<%= action.go_invocation_type %>) makeInputParams() map[string]interf
|
|
|
617
618
|
|
|
618
619
|
if inv.Input != nil {
|
|
619
620
|
<% action.input.parameters.each do |p| -%>
|
|
620
|
-
if inv.IsParameterSelected(
|
|
621
|
+
if inv.IsParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
621
622
|
<% if p.nillable? -%>
|
|
622
|
-
if inv.IsParameterNil(
|
|
623
|
-
ret[
|
|
623
|
+
if inv.IsParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
624
|
+
ret[<%= go_string_literal(p.name) %>] = nil
|
|
624
625
|
} else {
|
|
625
|
-
ret[
|
|
626
|
+
ret[<%= go_string_literal(p.name) %>] = inv.Input.<%= p.go_name %>
|
|
626
627
|
}
|
|
627
628
|
<% else -%>
|
|
628
|
-
ret[
|
|
629
|
+
ret[<%= go_string_literal(p.name) %>] = inv.Input.<%= p.go_name %>
|
|
629
630
|
<% end -%>
|
|
630
631
|
}
|
|
631
632
|
<% end -%>
|
|
@@ -641,15 +642,15 @@ func (inv *<%= action.go_invocation_type %>) makeInputParams() map[string]interf
|
|
|
641
642
|
|
|
642
643
|
if inv.MetaInput != nil {
|
|
643
644
|
<% action.metadata.global.input.parameters.each do |p| -%>
|
|
644
|
-
if inv.IsMetaParameterSelected(
|
|
645
|
+
if inv.IsMetaParameterSelected(<%= go_string_literal(p.go_name) %>) {
|
|
645
646
|
<% if p.nillable? -%>
|
|
646
|
-
if inv.IsMetaParameterNil(
|
|
647
|
-
ret[
|
|
647
|
+
if inv.IsMetaParameterNil(<%= go_string_literal(p.go_name) %>) {
|
|
648
|
+
ret[<%= go_string_literal(p.name) %>] = nil
|
|
648
649
|
} else {
|
|
649
|
-
ret[
|
|
650
|
+
ret[<%= go_string_literal(p.name) %>] = inv.MetaInput.<%= p.go_name %>
|
|
650
651
|
}
|
|
651
652
|
<% else -%>
|
|
652
|
-
ret[
|
|
653
|
+
ret[<%= go_string_literal(p.name) %>] = inv.MetaInput.<%= p.go_name %>
|
|
653
654
|
<% end -%>
|
|
654
655
|
}
|
|
655
656
|
<% end -%>
|
|
@@ -3,6 +3,8 @@ package <%= package %>
|
|
|
3
3
|
import (
|
|
4
4
|
"fmt"
|
|
5
5
|
"net/http"
|
|
6
|
+
"net/url"
|
|
7
|
+
"strings"
|
|
6
8
|
)
|
|
7
9
|
|
|
8
10
|
type OAuth2Auth struct {
|
|
@@ -11,32 +13,42 @@ type OAuth2Auth struct {
|
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
func (auth *OAuth2Auth) Authenticate(request *http.Request) {
|
|
14
|
-
request.Header.Set(
|
|
16
|
+
request.Header.Set(<%= go_string_literal(auth.http_header) %>, auth.AccessToken)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
//
|
|
19
|
+
// SetExistingOAuth2Auth will use a previously acquired access token
|
|
18
20
|
func (client *Client) SetExistingOAuth2Auth(accessToken string) {
|
|
19
21
|
client.Authentication = &OAuth2Auth{
|
|
20
22
|
AccessToken: accessToken,
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
//
|
|
26
|
+
// RevokeAccessToken will revoke the access token and remove authentication
|
|
25
27
|
// from the client
|
|
26
28
|
func (client *Client) RevokeAccessToken() error {
|
|
27
|
-
|
|
29
|
+
auth, ok := client.Authentication.(*OAuth2Auth)
|
|
30
|
+
if !ok {
|
|
31
|
+
return fmt.Errorf("OAuth2 authentication is not configured")
|
|
32
|
+
}
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
form := url.Values{}
|
|
35
|
+
form.Set("token", auth.AccessToken)
|
|
30
36
|
|
|
37
|
+
revokeURL, err := client.descriptionURL(<%= go_string_literal(auth.revoke_url) %>)
|
|
31
38
|
if err != nil {
|
|
32
39
|
return err
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
req, err := http.NewRequest("POST", revokeURL, strings.NewReader(form.Encode()))
|
|
43
|
+
|
|
44
|
+
if err != nil {
|
|
45
|
+
return err
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
49
|
+
auth.Authenticate(req)
|
|
50
|
+
|
|
51
|
+
resp, err := client.do(req)
|
|
40
52
|
|
|
41
53
|
if err != nil {
|
|
42
54
|
return err
|
|
@@ -8,10 +8,10 @@ import (
|
|
|
8
8
|
type Mode int
|
|
9
9
|
|
|
10
10
|
const (
|
|
11
|
-
// Send the token via HTTP header <%= auth.http_header %>
|
|
11
|
+
// Send the token via HTTP header <%= go_comment_text(auth.http_header) %>
|
|
12
12
|
HttpHeader Mode = iota
|
|
13
13
|
|
|
14
|
-
// Send the token via query parameter <%= auth.query_parameter %>
|
|
14
|
+
// Send the token via query parameter <%= go_comment_text(auth.query_parameter) %>
|
|
15
15
|
QueryParameter = iota
|
|
16
16
|
)
|
|
17
17
|
|
|
@@ -29,11 +29,11 @@ type TokenAuth struct {
|
|
|
29
29
|
func (auth *TokenAuth) Authenticate(request *http.Request) {
|
|
30
30
|
switch auth.Mode {
|
|
31
31
|
case HttpHeader:
|
|
32
|
-
request.Header.Set(
|
|
32
|
+
request.Header.Set(<%= go_string_literal(auth.http_header) %>, auth.Token)
|
|
33
33
|
|
|
34
34
|
case QueryParameter:
|
|
35
35
|
q := request.URL.Query()
|
|
36
|
-
q.Add(
|
|
36
|
+
q.Add(<%= go_string_literal(auth.query_parameter) %>, auth.Token)
|
|
37
37
|
request.URL.RawQuery = q.Encode()
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -95,20 +95,20 @@ func (auth *TokenAuth) setDefaultOptions(options *TokenAuthOptions) {
|
|
|
95
95
|
// the authentication is completed
|
|
96
96
|
func (auth *TokenAuth) nextAuthenticationStep(options *TokenAuthOptions, action string, token string) error {
|
|
97
97
|
<% auth.custom_actions.each do |a| -%>
|
|
98
|
-
if action ==
|
|
99
|
-
|
|
100
|
-
input :=
|
|
98
|
+
if action == <%= go_string_literal(a.name) %> {
|
|
99
|
+
request := auth.Resource.<%= a.go_name %>.Prepare()
|
|
100
|
+
input := request.NewInput()
|
|
101
101
|
input.SetToken(token)
|
|
102
102
|
|
|
103
103
|
if options.<%= "#{a.go_name}Callback" %> == nil {
|
|
104
|
-
return fmt.Errorf("Implement callback
|
|
104
|
+
return fmt.Errorf(<%= go_string_literal("Implement callback #{a.go_name}Callback") %>)
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if err := options.<%= "#{a.go_name}Callback" %>(input); err != nil {
|
|
108
|
-
return fmt.Errorf(
|
|
108
|
+
return fmt.Errorf(<%= go_string_literal("#{a.go_name}Callback failed: %v") %>, err)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
resp, err :=
|
|
111
|
+
resp, err := request.Call()
|
|
112
112
|
|
|
113
113
|
if err != nil {
|
|
114
114
|
return err
|
data/template/client.go.erb
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
package <%= package %>
|
|
2
2
|
|
|
3
|
+
import (
|
|
4
|
+
"net/http"
|
|
5
|
+
"time"
|
|
6
|
+
)
|
|
7
|
+
|
|
3
8
|
// Client represents a connection to an API server
|
|
4
9
|
type Client struct {
|
|
5
10
|
// API URL
|
|
@@ -8,15 +13,20 @@ type Client struct {
|
|
|
8
13
|
// Options for authentication method
|
|
9
14
|
Authentication Authenticator
|
|
10
15
|
|
|
16
|
+
httpClient *http.Client
|
|
17
|
+
|
|
11
18
|
<% api.resources.each do |r| -%>
|
|
12
|
-
// Resource <%= r.full_dot_name %>
|
|
19
|
+
// Resource <%= go_comment_text(r.full_dot_name) %>
|
|
13
20
|
<%= r.go_name %> *<%= r.go_type %>
|
|
14
21
|
<% end -%>
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
// Create a new client for API at url
|
|
18
25
|
func New(url string) *Client {
|
|
19
|
-
c := &Client{
|
|
26
|
+
c := &Client{
|
|
27
|
+
Url: url,
|
|
28
|
+
httpClient: http.DefaultClient,
|
|
29
|
+
}
|
|
20
30
|
|
|
21
31
|
<% api.resources.each do |r| -%>
|
|
22
32
|
c.<%= r.go_name %> = New<%= r.go_type %>(c)
|
|
@@ -24,3 +34,32 @@ func New(url string) *Client {
|
|
|
24
34
|
|
|
25
35
|
return c
|
|
26
36
|
}
|
|
37
|
+
|
|
38
|
+
// SetHTTPClient configures the HTTP client used for all requests.
|
|
39
|
+
func (client *Client) SetHTTPClient(httpClient *http.Client) {
|
|
40
|
+
if httpClient == nil {
|
|
41
|
+
client.httpClient = http.DefaultClient
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
client.httpClient = httpClient
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// SetTimeout configures an overall timeout for all HTTP requests.
|
|
49
|
+
func (client *Client) SetTimeout(timeout time.Duration) {
|
|
50
|
+
if client.httpClient == nil || client.httpClient == http.DefaultClient {
|
|
51
|
+
client.httpClient = &http.Client{Timeout: timeout}
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
client.httpClient.Timeout = timeout
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func (client *Client) do(req *http.Request) (*http.Response, error) {
|
|
59
|
+
httpClient := client.httpClient
|
|
60
|
+
if httpClient == nil {
|
|
61
|
+
httpClient = http.DefaultClient
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return httpClient.Do(req)
|
|
65
|
+
}
|
data/template/request.go.erb
CHANGED
|
@@ -3,17 +3,116 @@ package <%= package %>
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
5
|
"encoding/json"
|
|
6
|
+
"fmt"
|
|
6
7
|
"io/ioutil"
|
|
7
8
|
"net/http"
|
|
9
|
+
"net/url"
|
|
10
|
+
"strings"
|
|
8
11
|
)
|
|
9
12
|
|
|
13
|
+
func (client *Client) actionURL(path string) (string, error) {
|
|
14
|
+
if !strings.HasPrefix(path, "/") || strings.HasPrefix(path, "//") {
|
|
15
|
+
return "", fmt.Errorf("unsafe API action path %q", path)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ref, err := url.Parse(path)
|
|
19
|
+
if err != nil {
|
|
20
|
+
return "", err
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if ref.IsAbs() || ref.Host != "" || ref.User != nil {
|
|
24
|
+
return "", fmt.Errorf("unsafe API action path %q", path)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return client.sameOriginURL(client.Url + path)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func (client *Client) descriptionURL(rawURL string) (string, error) {
|
|
31
|
+
base, err := client.parsedBaseURL()
|
|
32
|
+
if err != nil {
|
|
33
|
+
return "", err
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ref, err := url.Parse(rawURL)
|
|
37
|
+
if err != nil {
|
|
38
|
+
return "", err
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ref.User != nil {
|
|
42
|
+
return "", fmt.Errorf("unsafe API description URL %q", rawURL)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resolved := base.ResolveReference(ref)
|
|
46
|
+
if !sameOrigin(base, resolved) {
|
|
47
|
+
return "", fmt.Errorf("API description URL %q is outside client origin", rawURL)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return resolved.String(), nil
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func (client *Client) sameOriginURL(rawURL string) (string, error) {
|
|
54
|
+
base, err := client.parsedBaseURL()
|
|
55
|
+
if err != nil {
|
|
56
|
+
return "", err
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
resolved, err := url.Parse(rawURL)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return "", err
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if !sameOrigin(base, resolved) {
|
|
65
|
+
return "", fmt.Errorf("request URL %q is outside client origin", rawURL)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return resolved.String(), nil
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func (client *Client) parsedBaseURL() (*url.URL, error) {
|
|
72
|
+
base, err := url.Parse(client.Url)
|
|
73
|
+
if err != nil {
|
|
74
|
+
return nil, err
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if base.Scheme == "" || base.Host == "" {
|
|
78
|
+
return nil, fmt.Errorf("invalid client URL %q", client.Url)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return base, nil
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func sameOrigin(a *url.URL, b *url.URL) bool {
|
|
85
|
+
return strings.EqualFold(a.Scheme, b.Scheme) &&
|
|
86
|
+
strings.EqualFold(a.Hostname(), b.Hostname()) &&
|
|
87
|
+
originPort(a) == originPort(b)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func originPort(u *url.URL) string {
|
|
91
|
+
port := u.Port()
|
|
92
|
+
if port != "" {
|
|
93
|
+
return port
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
switch strings.ToLower(u.Scheme) {
|
|
97
|
+
case "http":
|
|
98
|
+
return "80"
|
|
99
|
+
case "https":
|
|
100
|
+
return "443"
|
|
101
|
+
default:
|
|
102
|
+
return ""
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
10
106
|
// DoQueryStringRequests makes a HTTP requests in which input parameters are
|
|
11
107
|
// sent as query parameters.
|
|
12
108
|
func (client *Client) DoQueryStringRequest(path string, queryParams map[string]string, output interface{}) error {
|
|
13
|
-
|
|
14
|
-
|
|
109
|
+
requestURL, err := client.actionURL(path)
|
|
110
|
+
|
|
111
|
+
if err != nil {
|
|
112
|
+
return err
|
|
113
|
+
}
|
|
15
114
|
|
|
16
|
-
req, err := http.NewRequest("GET",
|
|
115
|
+
req, err := http.NewRequest("GET", requestURL, nil)
|
|
17
116
|
|
|
18
117
|
if err != nil {
|
|
19
118
|
return err
|
|
@@ -31,7 +130,7 @@ func (client *Client) DoQueryStringRequest(path string, queryParams map[string]s
|
|
|
31
130
|
|
|
32
131
|
req.URL.RawQuery = q.Encode()
|
|
33
132
|
|
|
34
|
-
resp, err :=
|
|
133
|
+
resp, err := client.do(req)
|
|
35
134
|
|
|
36
135
|
if err != nil {
|
|
37
136
|
return err
|
|
@@ -54,8 +153,7 @@ func (client *Client) DoQueryStringRequest(path string, queryParams map[string]s
|
|
|
54
153
|
// DoBodyRequest makes a HTTP requests in which the input parameters are sent
|
|
55
154
|
// within the request body, encoded in JSON.
|
|
56
155
|
func (client *Client) DoBodyRequest(method string, path string, params interface{}, output interface{}) error {
|
|
57
|
-
|
|
58
|
-
url := client.Url + path
|
|
156
|
+
requestURL, err := client.actionURL(path)
|
|
59
157
|
|
|
60
158
|
jsonData, err := json.Marshal(params)
|
|
61
159
|
|
|
@@ -63,7 +161,7 @@ func (client *Client) DoBodyRequest(method string, path string, params interface
|
|
|
63
161
|
return err
|
|
64
162
|
}
|
|
65
163
|
|
|
66
|
-
req, err := http.NewRequest(method,
|
|
164
|
+
req, err := http.NewRequest(method, requestURL, bytes.NewBuffer(jsonData))
|
|
67
165
|
|
|
68
166
|
if err != nil {
|
|
69
167
|
return err
|
|
@@ -75,7 +173,7 @@ func (client *Client) DoBodyRequest(method string, path string, params interface
|
|
|
75
173
|
client.Authentication.Authenticate(req)
|
|
76
174
|
}
|
|
77
175
|
|
|
78
|
-
resp, err :=
|
|
176
|
+
resp, err := client.do(req)
|
|
79
177
|
|
|
80
178
|
if err != nil {
|
|
81
179
|
return err
|