request.go raw

   1  package rest
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/json"
   6  	"fmt"
   7  	"io"
   8  	"net/http"
   9  	"net/url"
  10  )
  11  
  12  const (
  13  	contentType = "application/json"
  14  )
  15  
  16  // Request will be used by all repositories and the client.
  17  // The Request struct can be transformed to a http request with method, url and optional body.
  18  type Request struct {
  19  	// Endpoint is the api endpoint, without the server, which we will receive the request,
  20  	// like: '/products'
  21  	Endpoint string
  22  	// Parameters is a map of strings (url.Values) that will be used to add
  23  	// http query strings to the request, like '/domains?tags=123'
  24  	Parameters url.Values
  25  	// Body is left as an interface because the Request is not coupled to any specific Request.Body struct
  26  	Body interface{}
  27  	// TestMode is used when users want to tinker with the api without touching their real data
  28  	TestMode bool
  29  }
  30  
  31  // GetJSONBody returns the request object as a json byte array
  32  func (r *Request) GetJSONBody() ([]byte, error) {
  33  	return json.Marshal(r.Body)
  34  }
  35  
  36  // GetBodyReader returns an io.Reader for the json marshalled body of this request
  37  // this will be used by the writer used in the client.
  38  func (r *Request) GetBodyReader() (io.Reader, error) {
  39  	// try to get the marshalled body
  40  	body, err := r.GetJSONBody()
  41  	if err != nil {
  42  		return nil, fmt.Errorf("error when marshaling request: %w", err)
  43  	}
  44  
  45  	return bytes.NewReader(body), nil
  46  }
  47  
  48  // GetHTTPRequest generates and returns a http.Request object.
  49  // It does this with the Request struct and the basePath and method,
  50  // that are provided by the client itself.
  51  func (r *Request) GetHTTPRequest(basePath string, method string) (*http.Request, error) {
  52  	requestURL := basePath + r.Endpoint
  53  
  54  	var bodyReader io.Reader
  55  	if r.Body != nil {
  56  		reader, err := r.GetBodyReader()
  57  		if err != nil {
  58  			return nil, err
  59  		}
  60  
  61  		bodyReader = reader
  62  	}
  63  
  64  	request, err := http.NewRequest(method, requestURL, bodyReader)
  65  	if err != nil {
  66  		return nil, err
  67  	}
  68  
  69  	// set json headers, because our this library sends and expects that
  70  	request.Header.Set("Content-Type", contentType)
  71  	request.Header.Set("Accept", contentType)
  72  
  73  	// if TestMode is true we always add a test=1 http query string to the url,
  74  	// this is used when users want to tinker with the api without changing their production data
  75  	if r.TestMode {
  76  		// if Parameters is not set yet, we create a new url.Values and set it
  77  		if r.Parameters == nil {
  78  			r.Parameters = url.Values{}
  79  		}
  80  
  81  		r.Parameters.Add("test", "1")
  82  	}
  83  
  84  	// set the custom parameters on the rawquery
  85  	request.URL.RawQuery = r.Parameters.Encode()
  86  
  87  	return request, nil
  88  }
  89