code: function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload) {
    if (!isString(method)) {
      throw new TypeError('method should be of type "string"')
    }
    if (!isString(path)) {
      throw new TypeError('path should be of type "string"')
    }
    if (!isObject(headers)) {
      throw new TypeError('headers should be of type "object"')
    }
    if (!isArray(signedHeaders)) {
      throw new TypeError('signedHeaders should be of type "array"')
    }
    if (!isString(hashedPayload)) {
      throw new TypeError('hashedPayload should be of type "string"')
    }
    var headersArray = signedHeaders.reduce((acc, i) => {
      acc.push(`${i.toLowerCase()}:${headers[i]}`)
      return acc
    }, [])
  
    var requestResource = path.split('?')[0]
    var requestQuery = path.split('?')[1]
    if (!requestQuery) requestQuery = ''
  
    if (requestQuery) {
      requestQuery = requestQuery
        .split('&')
        .sort()
        .map(element => element.indexOf('=') === -1 ? element + '=' : element)
        .join('&')
    }
  
    var canonical = []
    canonical.push(method.toUpperCase())
    canonical.push(requestResource)
    canonical.push(requestQuery)
    canonical.push(headersArray.join('\n') + '\n')
    canonical.push(signedHeaders.join(';').toLowerCase())
    canonical.push(hashedPayload)
    return canonical.join('\n')
  }
docs: getCanonicalRequest generate a canonical request of style.  canonicalRequest = <HTTPMethod>\n <CanonicalURI>\n <CanonicalQueryString>\n <CanonicalHeaders>\n <SignedHeaders>\n <HashedPayload>