Consumer O-DU slice assurance rApp
[nonrtric/rapp/ransliceassurance.git] / icsversion / internal / restclient / client.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package restclient
22
23 import (
24         "bytes"
25         "encoding/json"
26         "fmt"
27         "io"
28         "net/http"
29         "net/http/httputil"
30
31         log "github.com/sirupsen/logrus"
32 )
33
34 type RequestError struct {
35         StatusCode int
36         Body       []byte
37 }
38
39 func (e RequestError) Error() string {
40         return fmt.Sprintf("error response with status: %v and body: %v", e.StatusCode, string(e.Body))
41 }
42
43 type Client struct {
44         httpClient *http.Client
45         verbose    bool
46 }
47
48 func New(httpClient *http.Client, verbose bool) *Client {
49         return &Client{
50                 httpClient: httpClient,
51                 verbose:    verbose,
52         }
53 }
54
55 func (c *Client) Get(path string, v interface{}, userInfo ...string) error {
56         var req *http.Request
57         var err error
58
59         if len(userInfo) > 1 {
60                 req, err = c.newRequest(http.MethodGet, path, nil, userInfo[0], userInfo[1])
61         } else {
62                 req, err = c.newRequest(http.MethodGet, path, nil)
63         }
64
65         if err != nil {
66                 return fmt.Errorf("failed to create GET request: %w", err)
67         }
68
69         if err := c.doRequest(req, v); err != nil {
70                 return err
71         }
72
73         return nil
74 }
75
76 func (c *Client) Post(path string, payload interface{}, v interface{}, userInfo ...string) error {
77         var req *http.Request
78         var err error
79
80         if len(userInfo) > 1 {
81                 req, err = c.newRequest(http.MethodPost, path, payload, userInfo[0], userInfo[1])
82         } else {
83                 req, err = c.newRequest(http.MethodPost, path, payload)
84         }
85
86         if err != nil {
87                 return fmt.Errorf("failed to create POST request: %w", err)
88         }
89
90         if err := c.doRequest(req, v); err != nil {
91                 return err
92         }
93
94         return nil
95 }
96
97 func (c *Client) Put(path string, payload interface{}, v interface{}, userInfo ...string) error {
98         var req *http.Request
99         var err error
100         if len(userInfo) > 1 {
101                 req, err = c.newRequest(http.MethodPut, path, payload, userInfo[0], userInfo[1])
102         } else {
103                 req, err = c.newRequest(http.MethodPut, path, payload)
104         }
105
106         if err != nil {
107                 return fmt.Errorf("failed to create PUT request: %w", err)
108         }
109
110         if err := c.doRequest(req, v); err != nil {
111                 return err
112         }
113
114         return nil
115 }
116
117 func (c *Client) Delete(path string, payload interface{}, v interface{}, userInfo ...string) error {
118         var req *http.Request
119         var err error
120         if len(userInfo) > 1 {
121                 req, err = c.newRequest(http.MethodDelete, path, payload, userInfo[0], userInfo[1])
122         } else {
123                 req, err = c.newRequest(http.MethodDelete, path, payload)
124         }
125
126         if err != nil {
127                 return fmt.Errorf("failed to create Delete request: %w", err)
128         }
129
130         if err := c.doRequest(req, v); err != nil {
131                 return err
132         }
133
134         return nil
135 }
136
137 func (c *Client) newRequest(method, path string, payload interface{}, userInfo ...string) (*http.Request, error) {
138         var reqBody io.Reader
139
140         if payload != nil {
141                 bodyBytes, err := json.Marshal(payload)
142                 if err != nil {
143                         return nil, fmt.Errorf("failed to marshal request body: %w", err)
144                 }
145                 reqBody = bytes.NewReader(bodyBytes)
146         }
147
148         req, err := http.NewRequest(method, path, reqBody)
149
150         if err != nil {
151                 return nil, fmt.Errorf("failed to create HTTP request: %w", err)
152         }
153
154         if len(userInfo) > 0 {
155                 req.SetBasicAuth(userInfo[0], userInfo[1])
156         }
157
158         if reqBody != nil {
159                 req.Header.Set("Content-Type", "application/json")
160         }
161
162         if c.verbose {
163                 if reqDump, error := httputil.DumpRequest(req, true); error != nil {
164                         fmt.Println(err)
165                 } else {
166                         fmt.Println(string(reqDump))
167                 }
168         }
169
170         return req, nil
171 }
172
173 func (c *Client) doRequest(r *http.Request, v interface{}) error {
174         resp, err := c.do(r)
175         if err != nil {
176                 return err
177         }
178
179         if resp == nil {
180                 return nil
181         }
182         defer resp.Body.Close()
183
184         if v == nil {
185                 return nil
186         }
187
188         dec := json.NewDecoder(resp.Body)
189         if err := dec.Decode(&v); err != nil {
190                 return fmt.Errorf("could not parse response body: %w [%s:%s]", err, r.Method, r.URL.String())
191         }
192         log.Debugf("Http Client Response: %v\n", v)
193         return nil
194 }
195
196 func (c *Client) do(r *http.Request) (*http.Response, error) {
197         resp, err := c.httpClient.Do(r)
198         if err != nil {
199                 return nil, fmt.Errorf("failed to make request [%s:%s]: %w", r.Method, r.URL.String(), err)
200         }
201
202         if c.verbose {
203                 if responseDump, error := httputil.DumpResponse(resp, true); error != nil {
204                         fmt.Println(err)
205                 } else {
206                         fmt.Println(string(responseDump))
207                 }
208         }
209
210         if resp.StatusCode >= http.StatusOK && resp.StatusCode <= 299 {
211                 return resp, nil
212         }
213
214         defer resp.Body.Close()
215         responseData, _ := io.ReadAll(resp.Body)
216
217         putError := RequestError{
218                 StatusCode: resp.StatusCode,
219                 Body:       responseData,
220         }
221
222         return resp, putError
223 }