utilities

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2020 License: BSD-3-Clause Imports: 11 Imported by: 0

README

Utilities

Table of Contents

Description

This package contains many functions and Go structs that are used by the Automated Checkout reference design.

Documentation

Each function in this package is documented. To see documentation, run the command go doc -all.

This package is mostly centered around building & writing instances of the HTTPResponse struct, which contains a payload like this:

type HTTPResponse struct {
	Content     interface{} `json:"content"`
	ContentType string      `json:"contentType"`
	StatusCode  int         `json:"statusCode"`
	Error       bool        `json:"error"`
}

In JSON:

{
	"content": "{}",
	"contentType": "string|json",
	"statusCode": 200,
	"error": false
}

Philosophically, this payload format has some advantages and disadvantages, which are discussed below in the REST API Payload Discussion section.

This package is not restricted to exporting only HTTP response-like functions and structs. It can hold any code that is intended to be used with Automated Checkout and EdgeX.

Requirements

This package has no dependencies or requirements aside from the essentials for Go development:

  • Git version 2.22+ (or latest supported version)
  • Go v1.12+

Setup

This package is intended to be used as part of a go.mod file with a reference to a locally cloned version of this repository - here's a modified example of another repository's go.mod file:

module as-vending

go 1.12

require (
	github.com/edgexfoundry/app-functions-sdk-go v1.0.0
	github.com/edgexfoundry/go-mod-core-contracts v0.1.14
	github.com/intel-iot-devkit/automated-checkout-utilities v1.0.0
)

This step should be all that is required in order for your project to work with automated-checkout-utilities.

Testing

To test, run:

make test

For an HTML readout of test coverage, run:

make testHTML
Linting

The Makefile in this repository leverages golangci-lint for in-depth linting, configured in .golangci.yml:

make lint

Configuration

There is no configuration needed for this package.

REST API Payload Discussion

REST API responses can be consistent when done right, for example, HTTP responses should have an accurate Content-Type header, such as text/plain or application/json. Additionally, response status codes such as 404, 200, and 500 help provide more useful information.

In the industry and in reality, REST API payload schemas are actually quite varied. For example, some companies always respond 200 OK even for errors or non-OK responses, and then have a consistent schema in their response body that indicates the actual information. Other companies use variations on the theme.

One situation that demonstrates the flaws of using only the HTTP status code is a 404 response. Does a 404 from the server mean that the endpoint does not exist, or that it was the correct endpoint, but the query yielded no results? This is one of the few but very frequently encountered cases of ambiguity that requires a bit more agreement of standardization across software projects.

In this particular project, the format of

{
	"content": "{}",
	"contentType": "string|json",
	"statusCode": 200,
	"error": false
}

has been chosen because it is the bare minimum of what's needed for each of the microservices to interact with each other. This format solves the above scenario of an ambiguous 404 by allowing error: true when the endpoint is not found, and error: false when the endpoint is found but the query yielded no results. Additionally, all payloads are of the format application/json, and the contentType field dictates whether the content is a string or JSON response to be marshaled in Go.

There is some redundancy, but the consistency allows for smoother interactions between microservices.

Disclaimer: The authors of the Automated Checkout reference design are not suggesting that all REST API schemas should follow this format. Please use REST API interaction schemas that meet your own use cases best.

Documentation

Index

Constants

View Source
const AllowedHeaders = "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, X-CSRF-Token"

AllowedHeaders is the set of headers we will process in the ProcessCORS function.

View Source
const HTTPResponseTypeJSON = "json"

HTTPResponseTypeJSON is a const that allows for efficiently setting HTTPResponse structs' ContentType fields to json

View Source
const HTTPResponseTypeString = "string"

HTTPResponseTypeString is a const that allows for efficiently setting HTTPResponse structs' ContentType fields to string

Variables

This section is empty.

Functions

func DeleteEmptyAndTrim

func DeleteEmptyAndTrim(s []string) []string

DeleteEmptyAndTrim takes an input string slice and trims whitespace surrounding each entry in the slice

func GenUUID

func GenUUID() string

GenUUID returns a fresh UUID as a string

func GetAsJSON

func GetAsJSON(input interface{}) (output string, err error)

GetAsJSON converts any interface into a JSON string

func GetGenericError

func GetGenericError(confKey string, confItemType reflect.Type) error

GetGenericError helps keep the ProcessApplicationSettings slim by enabling re-use of a common error format that should be returned to the user when the user fails to specify a configuration item.

func GetGenericParseError

func GetGenericParseError(confKey string, confValue interface{}, confItemType reflect.Type) error

GetGenericParseError helps keep the ProcessApplicationSettings slim by enabling re-use of a common error format that should be returned to the user when the user fails to specify a parseable configuration item.

func LoadFromJSONFile

func LoadFromJSONFile(filename string, target interface{}) (err error)

LoadFromJSONFile takes an input filename and loads from JSON into any interface Make sure that the "target" parameter is used like this err := LoadFromJSONFile(filename, &target)

func MarshalSettings

func MarshalSettings(settings map[string]string, config interface{}, strict bool) (err error)

MarshalSettings converts a map[string]string into a properly marshaled config interface{}. This is useful for converting an EdgeX Application Settings or Device Service Driver config map into a proper struct. Since values in these maps are strings, some assumptions are made about these values when marshaling them into their proper values. For example, a config interface that contains a field with type []string will assume that the corresponding field name's key in the map is a CSV string. This function does not cover every possible type in Go, so there are bound to be some issues converting. It contains the most common types. If the strict boolean is set to true, this function will error out when a value in the input map is not specified. Note that the config parameter must be a pointer to an interface. All fields in the config interface should be exported. The reflect module does not have the ability to modify unexported fields. Any unexported fields will simply be ignored.

func NowDate

func NowDate() string

NowDate simply returns the date in ISO8601 format

func ProcessCORS

func ProcessCORS(writer http.ResponseWriter, req *http.Request, fn HTTPFunc)

ProcessCORS is a decorator function that enables CORS preflight responses and sets CORS headers. Usage:

func GetSomething(writer http.ResponseWriter, req *http.Request) {
    helpers.ProcessCORS(writer, req, func(writer http.ResponseWriter, req *http.Request) {
        // do some logic with writer and req
    })
}

func ValidUUID

func ValidUUID(u string) bool

ValidUUID checks to see if a given string is a valid UUID

func WriteJSONHTTPResponse

func WriteJSONHTTPResponse(w http.ResponseWriter, req *http.Request, statusCode int, content interface{}, error bool)

WriteJSONHTTPResponse is a one-liner meant to quickly build out a JSON HTTPResponse, and then respond according to the given inputs

func WriteStringHTTPResponse

func WriteStringHTTPResponse(w http.ResponseWriter, req *http.Request, statusCode int, content interface{}, error bool)

WriteStringHTTPResponse is a one-liner meant to quickly build out a string HTTPResponse, and then respond according to the given inputs

func WriteToJSONFile

func WriteToJSONFile(filename string, target interface{}, perm os.FileMode) (err error)

WriteToJSONFile takes an input filename and writes JSON from any interface The "perm" parameter should generally be 0644

Types

type HTTPFunc

type HTTPFunc func(http.ResponseWriter, *http.Request)

HTTPFunc is a function type that matches what is typically passed into an HTTP API endpoint

type HTTPResponse

type HTTPResponse struct {
	Content     interface{} `json:"content"`
	ContentType string      `json:"contentType"`
	StatusCode  int         `json:"statusCode"`
	Error       bool        `json:"error"`
}

HTTPResponse All API HTTP responses should follow this format.

func GetHTTPResponseTemplate

func GetHTTPResponseTemplate() HTTPResponse

GetHTTPResponseTemplate gets a template HTTPResponse. You can use this as a starting point for all HTTP responses

func ParseJSONHTTPResponseContent

func ParseJSONHTTPResponseContent(respBody io.ReadCloser, outputJSONContent interface{}) (response HTTPResponse, err error)

ParseJSONHTTPResponseContent converts a raw http.Response (i.e. resp.Body) into a fully unmarshaled interface, including the content interface

func (HTTPResponse) GetAsString

func (response HTTPResponse) GetAsString() string

GetAsString gets an HTTPResponse as a JSON string. If the JSON marshal fails, it will return a template error HTTPResponse

func (*HTTPResponse) SetHTTPResponseFields

func (response *HTTPResponse) SetHTTPResponseFields(statusCode int, content interface{}, contentType string, error bool)

SetHTTPResponseFields sets the four HTTPResponse fields in a single line.

func (*HTTPResponse) SetJSONHTTPResponseFields

func (response *HTTPResponse) SetJSONHTTPResponseFields(statusCode int, content interface{}, error bool)

SetJSONHTTPResponseFields sets the three common HTTPResponse fields, and the ContentType to JSON

func (*HTTPResponse) SetStringHTTPResponseFields

func (response *HTTPResponse) SetStringHTTPResponseFields(statusCode int, content interface{}, error bool)

SetStringHTTPResponseFields sets the three common HTTPResponse fields, and the ContentType to string

func (*HTTPResponse) WriteHTTPResponse

func (response *HTTPResponse) WriteHTTPResponse(writer http.ResponseWriter, req *http.Request)

WriteHTTPResponse is a helpful shorthand for writing out a prepared HTTPResponse

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL