Skip to content

Commit 5d88a7e

Browse files
authored
Merge pull request #6 from CDimonaco/feature/custom_headers_in_client_definition
Add support for custom global headers
2 parents b51de17 + b9a5b47 commit 5d88a7e

File tree

2 files changed

+71
-18
lines changed

2 files changed

+71
-18
lines changed

client/client.go

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ import (
1717
)
1818

1919
type NgsiV2Client struct {
20-
c *http.Client
21-
url string
22-
timeout time.Duration
23-
apiRes *model.APIResources
20+
c *http.Client
21+
url string
22+
timeout time.Duration
23+
apiRes *model.APIResources
24+
customGlobalHeaders map[string]string
2425
}
2526

2627
// ClientOptionFunc is a function that configures a NgsiV2Client.
@@ -29,7 +30,8 @@ type ClientOptionFunc func(*NgsiV2Client) error
2930
// NewNgsiV2Client creates a new NGSIv2 client.
3031
func NewNgsiV2Client(options ...ClientOptionFunc) (*NgsiV2Client, error) {
3132
c := &NgsiV2Client{
32-
timeout: time.Second * 15,
33+
timeout: time.Second * 15,
34+
customGlobalHeaders: make(map[string]string),
3335
}
3436

3537
// apply the options
@@ -62,18 +64,33 @@ func SetUrl(url string) ClientOptionFunc {
6264
}
6365
}
6466

67+
// SetGlobalHeader is used a custom header applied to all the requests
68+
// made to the context broker
69+
func SetGlobalHeader(key string, value string) ClientOptionFunc {
70+
return func(c *NgsiV2Client) error {
71+
c.customGlobalHeaders[key] = value
72+
return nil
73+
}
74+
}
75+
6576
type additionalHeader struct {
6677
key string
6778
value string
6879
}
6980

70-
func newRequest(method, url string, body io.Reader, additionalHeaders ...additionalHeader) (*http.Request, error) {
81+
func (c *NgsiV2Client) newRequest(method, url string, body io.Reader, additionalHeaders ...additionalHeader) (*http.Request, error) {
7182
req, err := http.NewRequest(method, url, body)
7283
if err != nil {
7384
return nil, err
7485
}
7586
req.Header.Add("User-Agent", "ngsiv2-client")
7687
req.Header.Add("Accept", "application/json")
88+
89+
// set the global headers
90+
for header, value := range c.customGlobalHeaders {
91+
req.Header.Add(header, value)
92+
}
93+
7794
for _, ah := range additionalHeaders {
7895
req.Header.Add(ah.key, ah.value)
7996
}
@@ -85,7 +102,7 @@ func (c *NgsiV2Client) BatchUpdate(msg *model.BatchUpdate) error {
85102
if err != nil {
86103
return fmt.Errorf("Could not serialize message: %+v", err)
87104
}
88-
req, err := newRequest("POST", fmt.Sprintf("%s/v2/op/update", c.url), bytes.NewBuffer(jsonValue))
105+
req, err := c.newRequest("POST", fmt.Sprintf("%s/v2/op/update", c.url), bytes.NewBuffer(jsonValue))
89106
if err != nil {
90107
return fmt.Errorf("Could not create request for batch update: %+v", err)
91108
}
@@ -116,7 +133,7 @@ func (c *NgsiV2Client) BatchQuery(msg *model.BatchQuery, options ...BatchQueryPa
116133
if err != nil {
117134
return nil, fmt.Errorf("could not serialize message: %+v", err)
118135
}
119-
req, err := newRequest("POST", fmt.Sprintf("%s/v2/op/query", c.url), bytes.NewBuffer(jsonValue))
136+
req, err := c.newRequest("POST", fmt.Sprintf("%s/v2/op/query", c.url), bytes.NewBuffer(jsonValue))
120137
if err != nil {
121138
return nil, fmt.Errorf("could not create request for batch query: %+v", err)
122139
}
@@ -209,7 +226,7 @@ func BatchQuerySetOptions(opts string) BatchQueryParamFunc {
209226
// RetrieveAPIResources gives url link values for retrieving resources.
210227
// See: https://orioncontextbroker.docs.apiary.io/#reference/api-entry-point/retrieve-api-resources/retrieve-api-resources
211228
func (c *NgsiV2Client) RetrieveAPIResources() (*model.APIResources, error) {
212-
req, err := newRequest("GET", fmt.Sprintf("%s/v2", c.url), nil)
229+
req, err := c.newRequest("GET", fmt.Sprintf("%s/v2", c.url), nil)
213230
if err != nil {
214231
return nil, fmt.Errorf("Could not create request for API resources: %+v", err)
215232
}
@@ -355,7 +372,7 @@ func (c *NgsiV2Client) RetrieveEntity(id string, options ...RetrieveEntityParamF
355372
return nil, err
356373
}
357374

358-
req, err := newRequest("GET", fmt.Sprintf("%s/%s", eUrl, params.id), nil, params.headers()...)
375+
req, err := c.newRequest("GET", fmt.Sprintf("%s/%s", eUrl, params.id), nil, params.headers()...)
359376
if err != nil {
360377
return nil, fmt.Errorf("Could not create request for API resources: %+v", err)
361378
}
@@ -562,7 +579,7 @@ func (c *NgsiV2Client) ListEntities(options ...ListEntitiesParamFunc) ([]*model.
562579
return nil, err
563580
}
564581

565-
req, err := newRequest("GET", fmt.Sprintf("%s", eUrl), nil, params.headers()...)
582+
req, err := c.newRequest("GET", fmt.Sprintf("%s", eUrl), nil, params.headers()...)
566583
if err != nil {
567584
return nil, fmt.Errorf("Could not create request for API resources: %+v", err)
568585
}
@@ -647,7 +664,7 @@ func (c *NgsiV2Client) CountEntities(options ...ListEntitiesParamFunc) (int, err
647664
return 0, err
648665
}
649666

650-
req, err := newRequest("GET", fmt.Sprintf("%s", eUrl), nil, params.headers()...)
667+
req, err := c.newRequest("GET", fmt.Sprintf("%s", eUrl), nil, params.headers()...)
651668
if err != nil {
652669
return 0, fmt.Errorf("Could not create request for API resources: %+v", err)
653670
}
@@ -777,7 +794,7 @@ func (c *NgsiV2Client) CreateEntity(entity *model.Entity, options ...CreateEntit
777794
if err != nil {
778795
return "", false, fmt.Errorf("Could not serialize message: %v", err)
779796
}
780-
req, err := newRequest("POST", eUrl, bytes.NewBuffer(jsonEntity), params.headers()...)
797+
req, err := c.newRequest("POST", eUrl, bytes.NewBuffer(jsonEntity), params.headers()...)
781798
if err != nil {
782799
return "", false, fmt.Errorf("Could not create request for batch update: %v", err)
783800
}
@@ -851,7 +868,7 @@ func (c *NgsiV2Client) CreateSubscription(subscription *model.Subscription, opti
851868
if err != nil {
852869
return "", err
853870
}
854-
req, err := newRequest("POST", sUrl, bytes.NewBuffer(jsonValue), params.headers()...)
871+
req, err := c.newRequest("POST", sUrl, bytes.NewBuffer(jsonValue), params.headers()...)
855872
if err != nil {
856873
return "", fmt.Errorf("Could not create request for subscription creation: %+v", err)
857874
}
@@ -879,7 +896,7 @@ func (c *NgsiV2Client) RetrieveSubscription(id string) (*model.Subscription, err
879896
if err != nil {
880897
return nil, err
881898
}
882-
req, err := newRequest("GET", fmt.Sprintf("%s/%s", sUrl, id), nil)
899+
req, err := c.newRequest("GET", fmt.Sprintf("%s/%s", sUrl, id), nil)
883900
if err != nil {
884901
return nil, fmt.Errorf("Could not create request for subscription retrieval: %+v", err)
885902
}
@@ -976,7 +993,7 @@ func (c *NgsiV2Client) RetrieveSubscriptions(options ...RetrieveSubscriptionsPar
976993
if err != nil {
977994
return nil, err
978995
}
979-
req, err := newRequest("GET", sUrl, nil, params.headers()...)
996+
req, err := c.newRequest("GET", sUrl, nil, params.headers()...)
980997
if err != nil {
981998
return nil, fmt.Errorf("Could not create request for subscriptions retrieval: %+v", err)
982999
}
@@ -1041,7 +1058,7 @@ func (c *NgsiV2Client) UpdateSubscription(id string, patchSubscription *model.Su
10411058
}
10421059
}
10431060

1044-
req, err := newRequest("PATCH", fmt.Sprintf("%s/%s", sUrl, id), bytes.NewBuffer(jsonValue), params.headers()...)
1061+
req, err := c.newRequest("PATCH", fmt.Sprintf("%s/%s", sUrl, id), bytes.NewBuffer(jsonValue), params.headers()...)
10451062
if err != nil {
10461063
return fmt.Errorf("Could not create request for subscription updating: %+v", err)
10471064
}
@@ -1079,7 +1096,7 @@ func (c *NgsiV2Client) DeleteSubscription(id string, options ...SubscriptionPara
10791096
}
10801097
}
10811098

1082-
req, err := newRequest("DELETE", fmt.Sprintf("%s/%s", sUrl, id), nil, params.headers()...)
1099+
req, err := c.newRequest("DELETE", fmt.Sprintf("%s/%s", sUrl, id), nil, params.headers()...)
10831100
if err != nil {
10841101
return fmt.Errorf("Could not create request for subscription deletion: %+v", err)
10851102
}

client/client_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,3 +748,39 @@ func TestRetrieveEntitiesWithFiwareHeaders(t *testing.T) {
748748
t.Fatalf("Unexpected error: '%v'", err)
749749
}
750750
}
751+
752+
func TestGlobalHeadersSetInRequest(t *testing.T) {
753+
ts := httptest.NewServer(
754+
http.HandlerFunc(
755+
func(w http.ResponseWriter, r *http.Request) {
756+
if strings.HasSuffix(r.URL.Path, "/v2") {
757+
apiResourcesHandler(w, r)
758+
} else {
759+
if r.Header.Get("Authorization") != "Bearer testtoken" {
760+
t.Errorf("Expected 'Bearer testtoken' as global header in 'Authorization', got '%s'", r.Header.Get("Authorization"))
761+
}
762+
if r.Header.Get("X-Custom-Header") != "customValue" {
763+
t.Errorf("Expected 'customValue' as global header in 'X-Custom-Header', got '%s'", r.Header.Get("X-Custom-Header"))
764+
}
765+
w.Header().Set("Content-Type", "application/json")
766+
w.WriteHeader(http.StatusOK)
767+
fmt.Fprint(w, `[{"id":"r2","type":"Room","pressure":{"type":"Integer","value":"720","metadata":{}},"temperature":{"type":"Float","value":34,"metadata":{}}},{"id":"r5","type":"Room","pressure":{"type":"Integer","value":"700","metadata":{}},"temperature":{"type":"Float","value":31,"metadata":{}}}
768+
]`)
769+
}
770+
}))
771+
defer ts.Close()
772+
773+
cli, err := client.NewNgsiV2Client(
774+
client.SetUrl(ts.URL),
775+
client.SetGlobalHeader("Authorization", "Bearer testtoken"),
776+
client.SetGlobalHeader("X-Custom-Header", "customValue"),
777+
)
778+
if err != nil {
779+
t.Fatalf("Unexpected error: '%v'", err)
780+
}
781+
782+
if _, err := cli.ListEntities(
783+
client.ListEntitiesSetType("Room")); err != nil {
784+
t.Fatalf("Unexpected error: '%v'", err)
785+
}
786+
}

0 commit comments

Comments
 (0)