diff --git a/rest-api-client.sh b/rest-api-client.sh index dbfb0440f2f7dde85c340b70b9bf6f35ec95bf33..2a55f363374498332234b5d9f4779e558b06240d 100644 --- a/rest-api-client.sh +++ b/rest-api-client.sh @@ -15,15 +15,10 @@ # 2020-02-12 v0.4 axel.hahn@iml.unibe.ch Caching # 2020-03-02 v0.5 axel.hahn@iml.unibe.ch a few more response check functions # 2021-01-21 v0.6 axel.hahn@iml.unibe.ch add Content-type in request header +# 2022-01-11 v0.7 axel.hahn@iml.unibe.ch fixes using shellcheck # ====================================================================== -# --- fetch incoming params - RestApiCfg=$1 - RestApiMethod=$2 - ApiUrl=$3 - Body="$4" - - http_cfg__about="Bash REST API client v0.6" + http_cfg__about="Bash REST API client v0.7" typeset -i http_cfg__debug=0 typeset -i http_cfg__cacheTtl=0 http_cfg__cacheDir=/var/tmp/http-cache @@ -103,7 +98,7 @@ EOH } function http.init(){ - + http._wd "${FUNCNAME[0]}()" which curl >/dev/null || http.quit # request vars @@ -116,7 +111,7 @@ EOH http_req__fullurl= http_req__docs= - http_req__dataprefix="RESTAPICLIENTMETADATA_`date +%s`_$$" + http_req__dataprefix="RESTAPICLIENTMETADATA_$(date +%s)_$$" local writevar= for myvar in $curlMeta do @@ -137,13 +132,15 @@ EOH } # execute the request + # param string optional: method; GET|POST|PUT|DELETE|... # param string optional: full url + # param string optional: request body function http.makeRequest(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" # --- handle optional prams if [ $# -ne 0 ]; then - echo $1 | grep "^[A-Z]*$" >/dev/null + echo "$1" | grep "^[A-Z]*$" >/dev/null if [ $? -eq 0 ]; then http.setMethod "$1" shift 1 @@ -157,14 +154,15 @@ EOH http_req__mode=REQUEST useCache=0 makeRequest=1 - if [ $http_cfg__cacheTtl -gt 0 -a "${http_req__method}" = "GET" ]; then + if [ $http_cfg__cacheTtl -gt 0 ] && [ "${http_req__method}" = "GET" ]; then useCache=1 - test -z "${http_cfg__cacheFile}" && http_cfg__cacheFile=`http._genOutfilename "${http_cfg__cacheDir}/AUTOFILE"` + test -z "${http_cfg__cacheFile}" && http_cfg__cacheFile=$(http._genOutfilename "${http_cfg__cacheDir}/AUTOFILE") if [ -f "${http_cfg__cacheFile}" ]; then http.responseImport "${http_cfg__cacheFile}" - typeset -i local iAge=`http.getRequestAge` + typeset -i local iAge + iAge=$(http.getRequestAge) http._wd "INFO: Age of cache is $iAge sec - vs TTL $http_cfg__cacheTtl sec - file $http_cfg__cacheFile" - if [ $iAge -gt 0 -a $iAge -lt $http_cfg__cacheTtl ]; then + if [ $iAge -gt 0 ] && [ $iAge -lt $http_cfg__cacheTtl ]; then http._wd "INFO: Using cache" makeRequest=0 http_req__mode=CACHE @@ -178,7 +176,6 @@ EOH # --- make the request if [ $makeRequest -eq 1 ]; then - http_req__start=`date +%s` http._wd "${FUNCNAME[0]}($1) ${http_req__method} ${http_req__fullurl}" http_resp__all=$( if [ -z "${http_req__body}" ]; then @@ -203,13 +200,13 @@ EOH fi ) || http.quit http._wd "OK - Curl finished the http request ... processing data" - http_resp__neutral=`http._fetchAllAndReformat` + http_resp__neutral=$(http._fetchAllAndReformat) if [ $useCache -eq 1 ]; then http._wd "INFO: writing cache ..." http.responseExport "${http_cfg__cacheFile}" fi fi - http._wd "Request function finished; Code `http.getStatuscode`" + http._wd "Request function finished; Code $(http.getStatuscode)" } # ...................................................................... @@ -217,8 +214,8 @@ EOH # show error message with last return code and quit with this exitcode # no params function http.quit(){ - http._wd "${FUNCNAME[0]}($1)" rc=$? + http._wd "${FUNCNAME[0]}()" echo >&2 echo -e "\e[31m# ERROR: command FAILED with rc $rc. \e[0m" >&2 if [ ! -z "${RestApiDocs}" ]; then @@ -242,7 +239,7 @@ EOH . "${1}" || http.quit # set "internal" vars - if [-z "$RestApiPassword" ]; then + if [ -z "$RestApiPassword" ]; then http.setAuth "$RestApiUser:$RestApiPassword" else http.setAuth @@ -254,6 +251,9 @@ EOH # ====================================================================== # GETTER # ====================================================================== + + # get the response header or response body + # param string what to return; one of header|body function http._fetchResponseHeaderOrBody(){ http._wd "${FUNCNAME[0]}($1)" local isheader=true @@ -275,24 +275,25 @@ EOH done } function http._fetchResponseData(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" echo "${http_resp__all}" | sed "s#${http_req__dataprefix}#\n${http_req__dataprefix}#" | grep "${http_req__dataprefix}" | tail -1 | cut -f 2- -d "|" | sed "s#|#\n#g" | grep -v "${http_req__dataprefix}" | while read -r line; do - echo $line + echo "$line" done } + function http._fetchAllAndReformat(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" IFS='' line="#------------------------------------------------------------" echo "#_META_|about:$http_cfg__about" - echo "#_META_|host:`hostname -f`" + echo "#_META_|host:$(hostname -f)" echo $line echo "#_REQUEST_|fullurl:$http_req__fullurl" echo "#_REQUEST_|method:$http_req__method" - echo "#_REQUEST_|time:`date`" - echo "#_REQUEST_|timestamp:`date +%s`" - echo "#_REQUEST_|auth:`echo $http_req__auth | sed 's#:.*#:xxxxxxxx#'`" + echo "#_REQUEST_|time:$(date)" + echo "#_REQUEST_|timestamp:$(date +%s)" + echo "#_REQUEST_|auth:$(echo $http_req__auth | sed 's#:.*#:xxxxxxxx#')" echo "#_REQUEST_|body:$http_req__body" echo "#_REQUEST_|baseurl:$http_req__baseurl" echo "#_REQUEST_|url:$http_req__url" @@ -314,39 +315,42 @@ EOH # ---------- PUBLIC REQUEST GETTER function http.getRequestTs(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http._getFilteredResponse REQUEST | grep "^timestamp" | cut -f 2 -d ":" } # get age of the response in sec. # It is especially useful after responseImport function http.getRequestAge(){ - http._wd "${FUNCNAME[0]}($1)" - typeset -i local iAge=`date +%s`-`http.getRequestTs` - echo $iAge + http._wd "${FUNCNAME[0]}()" + typeset -i local iAge + typeset -i local iTs + iTs=$( http.getRequestTs ) + iAge=$( date +%s )-${iTs} + echo "$iAge" } # ---------- PUBLIC RESPONSE GETTER # get response body function http.getResponse(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http._getFilteredResponse BODY } # get curl data of this request with status, transferred bytes, speed, ... function http.getResponseData(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http._getFilteredResponse DATA } # get response header function http.getResponseHeader(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http._getFilteredResponse HEADER } # get raw response (not available after import) function http.getResponseRaw(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" echo "${http_resp__all}" } @@ -360,8 +364,7 @@ EOH # get Http status code of the request as 3 digit number function http.getStatuscode(){ - http._wd "${FUNCNAME[0]}($1)" - local _filter=$1 + http._wd "${FUNCNAME[0]}()" http.getResponseData | grep "^http_code:" | cut -f 2 -d ":" } @@ -371,35 +374,35 @@ EOH # $? -eq 0 means YES # $? -ne 0 means NO function http.isOk(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.getStatuscode | grep '2[0-9][0-9]' } # was the repsonse a redirect? function http.isRedirect(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.getStatuscode | grep '3[0-9][0-9]' } # was the repsonse a client error (4xx or 5xx) function http.isError(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.getStatuscode | grep '[45][0-9][0-9]' } # was the repsonse a client error (4xx) function http.isClientError(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.getStatuscode | grep '4[0-9][0-9]' } # was the repsonse a client error (5xx) function http.isServerError(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.getStatuscode | grep '5[0-9][0-9]' } # dump information about request and response function http.dump(){ - http._wd "${FUNCNAME[0]}($1)" + http._wd "${FUNCNAME[0]}()" http.responseExport } @@ -411,37 +414,42 @@ EOH # param string import or export filename function http._genOutfilename(){ http._wd "${FUNCNAME[0]}($1)" - echo $1 | grep "AUTOFILE" >/dev/null + echo "$1" | grep "AUTOFILE" >/dev/null if [ $? -ne 0 ]; then echo $1 else - local sum=`echo ${http_req__fullurl} | sha1sum ` - local autofile=`echo "${sum}__${http_req__fullurl}" | sed "s#[^a-z0-9]#_#g"` - echo $1 | sed "s#AUTOFILE#${autofile}#" + local sum + sum=$(echo ${http_req__fullurl} | sha1sum ) + local autofile + autofile=$(echo "${sum}__${http_req__fullurl}" | sed "s#[^a-z0-9]#_#g") + echo "$1" | sed "s#AUTOFILE#${autofile}#" fi } - # export to a file + # export response to a file + # param string optional: custom filename function http.responseExport(){ http._wd "${FUNCNAME[0]}($1)" - if [ -z $1 ]; then + if [ -z "$1" ]; then echo "${http_resp__neutral}" else - local outfile=`http._genOutfilename "$1"` + local outfile + outfile=$(http._genOutfilename "$1") http._wd "${FUNCNAME[0]}($1) writing to outfile $outfile" - echo "${http_resp__neutral}" >$outfile + echo "${http_resp__neutral}" >"$outfile" fi } # import a former response from a file function http.responseImport(){ http._wd "${FUNCNAME[0]}($1)" - local infile=`http._genOutfilename "$1"` + local infile + infile=$(http._genOutfilename "$1") if [ -r "${infile}" ]; then grep "^#_META_|about:$http_cfg__about" "${infile}" >/dev/null if [ $? -eq 0 ]; then - http_resp__neutral=`cat "${infile}"` + http_resp__neutral=$(cat "${infile}") else echo "ERROR: Ooops [${infile}] does not seem to be an export dump." http.quit @@ -455,7 +463,8 @@ EOH # AUTOFILE functionality function http.responseDelete(){ http._wd "${FUNCNAME[0]}($1)" - local infile=`http._genOutfilename "$1"` + local infile + infile=$(http._genOutfilename "$1") if [ -r "${infile}" ]; then grep "^#_META_|about:$http_cfg__about" "${infile}" >/dev/null if [ $? -eq 0 ]; then @@ -499,7 +508,7 @@ EOH function http.setBaseUrl(){ http._wd "${FUNCNAME[0]}($1)" http_req__baseurl=$1 - http.setFullUrl + http.setFullUrl "" } # Enable or disable debug mode # param integer 0|1 @@ -520,7 +529,7 @@ EOH } # set a full url to request - # param string url + # param string optional: url function http.setFullUrl(){ http._wd "${FUNCNAME[0]}($1)" if [ -z "$1" ]; then @@ -653,7 +662,7 @@ INSTRUCTION: Get the http status as string Ok|Redirect|Error http.getStatuscode - Get the http status code of a request as integer + Get the http status code of a request as 3 digit integer http.isOk Check if the http response code is a 2xx