diff --git a/docs/20_Changelog.md b/docs/20_Changelog.md new file mode 100644 index 0000000000000000000000000000000000000000..52512ae70b83b7a97425acb9770dc08cd018c859 --- /dev/null +++ b/docs/20_Changelog.md @@ -0,0 +1,11 @@ +## Changelog + +### v0.11 (2024-11-20) + +This release was published to disable insecure requests. + +⌠Removed: curl default parameter `-k` (it disables ssl verification) +âš ï¸ Deprecated: The new filename is `http.class.sh`. When using `rest-api-client.sh` you get a deprecated warning on STDERR +🔷 Added: function `http.setInsecure` - set "1" to enable `-k` again; use no parameter to disable +🔷 Added: function `http.setCA "<file>"` to define a custom ca file (results in `--cacert <file>`) +🔷 Added: function `http.addCurlparam "<parameter>"` to add any missing curl parameter diff --git a/docs/20_Installation.md b/docs/20_Installation.md index 8028dabbe5ca0460abf3ca47126d259cac9ecd91..e7743152119b75157a92f8c42ce06b9d9af92f1e 100644 --- a/docs/20_Installation.md +++ b/docs/20_Installation.md @@ -18,11 +18,11 @@ Download the archive i.e. as zip: #### Copy shell script somewhere -Copy the file `rest-api-client.sh` anywhere you need it. +Copy the file `http.class.sh` anywhere you need it. If you need it in a single script then copy it to its directory. If you need it more often then copy it to a folter of your PATH environment. ### Get the script only For pure functionality without docs and more you can download the script itself -`wget https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/raw/master/rest-api-client.sh` +`wget https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/raw/master/http.class.sh` diff --git a/docs/30_Quickstart.md b/docs/30_Quickstart.md index 132394af1f9720c0c3d289b10d9687410114749f..25259b0d46ca92afac30aee3087ef9b4ca984ad8 100644 --- a/docs/30_Quickstart.md +++ b/docs/30_Quickstart.md @@ -1,6 +1,6 @@ ## Source the script -You must source the rest-api-client.sh. Then its functions are usable in the current process. +You must source the `http.class.sh`. Then its functions are usable in the current process. The "methods" start with "http" dot "[method]". ## Initialize a new request @@ -32,7 +32,7 @@ Now you can get its data, eg #!/bin/bash cd "$( dirname "$0" )" || exit -. ../rest-api-client.sh || exit 1 +. ../http.class.sh || exit 1 http.init http.makeRequest GET "http://www.example.com/" diff --git a/docs/40_Usage.md b/docs/40_Usage.md index 6cb16b612a4179d002a1980b7ca89c933f8febc9..c43d79acb7e76fd2990951c9af3d63265e30bf01 100644 --- a/docs/40_Usage.md +++ b/docs/40_Usage.md @@ -2,13 +2,13 @@ ### Source the script -You must source the rest-api-client.sh. Then its functions are usable in the current process. +You must source the `http.class.sh`. Then its functions are usable in the current process. The "methods" start with "http" dot "[method]". ```sh #!/bin/bash cd "$( dirname "$0" )" || exit -. ./rest-api-client.sh || exit 1 +. ./http.class.sh || exit 1 ``` @@ -88,9 +88,12 @@ Define a base url that will be used as prefix when making a request to a relativ #### Other funtions * `http.setAccept <ACCEPT>` -* `http.setDocs URL` http.setMethod METHOD Set a http method. Use an uppercase string for GET|POST|PUT|DELETE|... -* `http.addHeader HEADER_LINE` Add a header line to the request. This command can be repeated multiple times. -* `http.setDocs` Set a docs url. If set it will be shown as additional hint when a request fails. +* `http.setMethod <METHOD>` Set a http method. Use an uppercase string for GET|POST|PUT|DELETE|... (any method) +* `http.setCA <FILE>` Set a ca cert file (it results in --cacert \<file\>). Without parameter this flag will be removed. +* `http.setDocs <URL>` Set a docs url. If set it will be shown as additional hint when a request fails. +* `http.setInsecure 1` Do not verify SSL certificate (it results in `-k` parameter not recommended). Without parameter this flag will be removed. +* `http.addHeader <HEADER_LINE>` Add a header line to the request. This command can be repeated multInsecure 1 +* `http.addCurlparam <parameter>` Add any mising curl parameter when making the requests. This command can be repeated multiple times. ## Make a request @@ -263,14 +266,14 @@ You can run `http.help` to get an overwiew over all functions. # # step one: source the shell script # -$ . ./rest-api-client.sh +$ . ./http.class.sh # # then use its functions. # $ http.help -Bash REST API client v0.10 +Bash REST API client v0.11 This is a bash solution to script REST API calls. @@ -316,10 +319,20 @@ INSTRUCTION: renmark: Use http.setUrl to built a complete url. + http.setCA "<FILE>" + Set CA file to verify the server certificate. + Default: [empty] = use system defaults + Without parameter the cafile is removed + http.setDocs "<URL>" Set a docs url. If set it will be shown as additional hint when a request fails. + http.setInsecure 1 + Set insecure flag by giving any non empty value. + Default: [empty] = secure requests + Without parameter the insecure flag is removed + http.setMethod "<METHOD>" Set a http method. Use an uppercase string for GET|POST|PUT|DELETE|... @@ -332,7 +345,12 @@ INSTRUCTION: http.addHeader "<HEADER_LINE>" Add a header line to the request. - This command can be repeated multiple times. + This command can be repeated multiple times to add multiple headers. + + http.addCurlparam "<CURL_PARAMETER>" + Add any missing parameter for curl requestst. + This command can be repeated multiple times to add multiple prameters. + You also can add multiple parameters with one command. - caching functions @@ -417,7 +435,6 @@ INSTRUCTION: Example: http.makeRequest "https://example.com/api/" http.responseExport /tmp/something_AUTOFILE_.txt - http.responseImport "<FILE>" Import an export file. To use the AUTOFILE mechanism from export set diff --git a/docs/50_Examples.md b/docs/50_Examples.md index 1a8c8577d912a6d17092f0f1ab7d82a2705fca56..51e3b9a22141341cb4049af8afcaf47134a2c8d1 100644 --- a/docs/50_Examples.md +++ b/docs/50_Examples.md @@ -4,7 +4,7 @@ A required step is sourcing the script to make the http.* function available in ```sh # --- source script -> . ./rest-api-client.sh +> . ./http.class.sh ``` Then you can follow the examples. diff --git a/docs/99_Functions/rest-api-client.sh.md b/docs/99_Functions/http.class.sh.md similarity index 51% rename from docs/99_Functions/rest-api-client.sh.md rename to docs/99_Functions/http.class.sh.md index 7ee93f17da7a40f69796258c2b2cbdf95d19a40a..b0ad8ead987da80ac0e870424e8eac31ddcc2133 100644 --- a/docs/99_Functions/rest-api-client.sh.md +++ b/docs/99_Functions/http.class.sh.md @@ -1,10 +1,22 @@ -## rest-api-client.sh +## http.class.sh List of all functions in alphabetic order ### http() -[line: 96](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L96) +[line: 97](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L97) + +### http.addCurlparam() + +```txt + +Add an additional curl parameter + +🟩 param string line to add, eg "Connection: keep-alive" + +``` + +[line: 701](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L701) ### http.addHeader() @@ -16,7 +28,7 @@ Add a line to the request header ``` -[line: 682](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L682) +[line: 690](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L690) ### http.dump() @@ -28,7 +40,7 @@ no params ``` -[line: 577](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L577) +[line: 585](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L585) ### http.flushCache() @@ -40,7 +52,7 @@ no params ``` -[line: 842](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L842) +[line: 884](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L884) ### http.getRequestAge() @@ -55,7 +67,7 @@ returns integer age of the response in sec ``` -[line: 424](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L424) +[line: 432](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L432) ### http.getRequestTs() @@ -69,7 +81,7 @@ returns string the timestamp of the response ``` -[line: 410](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L410) +[line: 418](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L418) ### http.getResponse() @@ -83,7 +95,7 @@ returns string the response body ``` -[line: 443](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L443) +[line: 451](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L451) ### http.getResponseData() @@ -97,7 +109,7 @@ returns string the response data ``` -[line: 456](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L456) +[line: 464](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L464) ### http.getResponseHeader() @@ -111,7 +123,7 @@ returns string the response header ``` -[line: 469](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L469) +[line: 477](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L477) ### http.getResponseRaw() @@ -125,7 +137,7 @@ no param ``` -[line: 482](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L482) +[line: 490](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L490) ### http.getStatus() @@ -137,7 +149,7 @@ no params ``` -[line: 493](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L493) +[line: 501](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L501) ### http.getStatuscode() @@ -149,7 +161,7 @@ no params ``` -[line: 506](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L506) +[line: 514](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L514) ### http.help() @@ -161,7 +173,7 @@ no params ``` -[line: 853](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L853) +[line: 895](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L895) ### http.init() @@ -174,7 +186,7 @@ function. It will reset all variables. ``` -[line: 117](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L117) +[line: 118](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L118) ### http.isClientError() @@ -186,7 +198,7 @@ no params ``` -[line: 555](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L555) +[line: 563](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L563) ### http.isError() @@ -198,7 +210,7 @@ no params ``` -[line: 544](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L544) +[line: 552](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L552) ### http.isOk() @@ -215,7 +227,7 @@ no params ``` -[line: 522](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L522) +[line: 530](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L530) ### http.isRedirect() @@ -227,7 +239,7 @@ no params ``` -[line: 533](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L533) +[line: 541](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L541) ### http.isServerError() @@ -239,7 +251,7 @@ no params ``` -[line: 566](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L566) +[line: 574](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L574) ### http.loadcfg() @@ -265,7 +277,7 @@ The function will then set the "internal" vars ``` -[line: 285](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L285) +[line: 293](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L293) ### http.makeRequest() @@ -287,7 +299,7 @@ This function does the following: ``` -[line: 169](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L169) +[line: 173](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L173) ### http.quit() @@ -309,7 +321,7 @@ no params ``` -[line: 252](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L252) +[line: 260](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L260) ### http.responseDelete() @@ -322,7 +334,7 @@ AUTOFILE functionality ``` -[line: 653](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L653) +[line: 661](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L661) ### http.responseExport() @@ -334,7 +346,7 @@ Export response to a file ``` -[line: 611](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L611) +[line: 619](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L619) ### http.responseImport() @@ -346,7 +358,7 @@ Import a former response from a file ``` -[line: 629](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L629) +[line: 637](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L637) ### http.setAccept() @@ -358,7 +370,7 @@ set Accept request header and override default ``` -[line: 693](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L693) +[line: 712](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L712) ### http.setAuth() @@ -371,7 +383,7 @@ Without given parameter, authentication is removed ``` -[line: 709](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L709) +[line: 728](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L728) ### http.setAuthorization() @@ -385,7 +397,7 @@ Without given parameter, authorization is removed ``` -[line: 726](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L726) +[line: 745](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L745) ### http.setBaseUrl() @@ -398,7 +410,7 @@ Remark: Then use http.setUrl to complet the url to request ``` -[line: 753](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L753) +[line: 772](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L772) ### http.setBody() @@ -410,7 +422,19 @@ Set body to send for PUTs and POSTs ``` -[line: 741](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L741) +[line: 760](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L760) + +### http.setCA() + +```txt + +set and unset CA cert file to use + +🔹 param string optional: filename to use; no value to disable cafile + +``` + +[line: 784](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L784) ### http.setCacheFile() @@ -422,7 +446,7 @@ Set cache file ``` -[line: 831](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L831) +[line: 873](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L873) ### http.setCacheTtl() @@ -434,7 +458,7 @@ Set cache ttl in seconds ``` -[line: 820](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L820) +[line: 862](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L862) ### http.setDebug() @@ -446,11 +470,11 @@ Enable or disable debug mode ``` -[line: 765](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L765) +[line: 795](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L795) ### http.setDocs() -[line: 769](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L769) +[line: 801](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L801) ### http.setFullUrl() @@ -462,7 +486,19 @@ Set a full url to request ``` -[line: 791](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L791) +[line: 833](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L833) + +### http.setInsecure() + +```txt + +Allow and disallow insecure connections + +🔹 param string optional: 1 to enable insecure flag; no value to disable insecure flag + +``` + +[line: 811](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L811) ### http.setMethod() @@ -474,7 +510,7 @@ Set the method to use; GET|POST|PUT|DELETE|... ``` -[line: 780](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L780) +[line: 822](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L822) ### http.setUrl() @@ -486,7 +522,7 @@ Complete the base url ``` -[line: 806](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/rest-api-client.sh#L806) +[line: 848](https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/http.class.sh#L848) - - - Generated with [Bashdoc](https://github.com/axelhahn/bashdoc) v0.6 diff --git a/http.class.sh b/http.class.sh new file mode 100644 index 0000000000000000000000000000000000000000..1061a0e59f27209066848d8f313a7e3071445b4a --- /dev/null +++ b/http.class.sh @@ -0,0 +1,1084 @@ +#!/bin/bash +# ====================================================================== +# +# REST API CLIENT USING CURL +# +# REQUIREMENTS +# - Bash (Linux or MS Windows i.e with Cygwin) +# - curl +# - sha1sum (optional; for export functionality with AUTOFILE only) +# ---------------------------------------------------------------------- +# License: GPL 3.0 +# Source: <https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client> +# Docs: <https://os-docs.iml.unibe.ch/bash-rest-api-client/> +# ---------------------------------------------------------------------- +# (1) source this script +# (2) enter "http.help" to get a list of available commands +# ---------------------------------------------------------------------- +# 2020-02-07 v0.2 axel.hahn@iml.unibe.ch BETABETA +# 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 +# 2024-10-09 v0.8 axel.hahn@unibe.ch add setAuthorization; customize accept header, add custom request headers +# 2024-10-10 v0.9 axel.hahn@unibe.ch update docs +# 2024-10-23 v0.10 axel.hahn@unibe.ch update help +# 2024-11-20 v0.11 axel.hahn@unibe.ch no insecure requests by default; add setInsecure, setCA, addCurlparam +# ====================================================================== + + http_cfg__about="Bash REST API client v0.11" + typeset -i http_cfg__debug=0 + typeset -i http_cfg__cacheTtl=0 + http_cfg__cacheDir=/var/tmp/http-cache + http_cfg__UA="${http_cfg__about}" + http_cfg__prjurl="https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client" + http_cfg__docsurl="https://os-docs.iml.unibe.ch/bash-rest-api-client/" + +# --- curl meta infos to collect +# see variables in man curl --write-out param + curlMeta="\ + http_code \ + http_connect \ + local_ip \ + local_port \ + num_connects \ + num_redirects \ + redirect_url \ + remote_ip \ + remote_port \ + size_download \ + size_header \ + size_request \ + size_upload \ + speed_download \ + speed_upload \ + ssl_verify_result \ + time_appconnect \ + time_connect \ + time_namelookup \ + time_pretransfer \ + time_redirect \ + time_starttransfer \ + time_total \ + url_effective \ +" + + +# ---------------------------------------------------------------------- +# +# functions +# +# ---------------------------------------------------------------------- + + # ...................................................................... + # + # Write a debug message to STDERR + # Do no not change the prefix - is is read in inc_functions + # + # params strings output message + # + function http._wd(){ + if [ $http_cfg__debug -gt 0 ]; then + echo -e "\e[33m# RESTAPI::DEBUG $*\e[0m" >&2 + fi + } + + # ...................................................................... + # + # Write an error message to STDERR + # Do no not change the prefix - is is read in inc_functions + # + # params strings output message + # + function http._we(){ + echo -e "\e[31m# RESTAPI::ERROR $*\e[0m" >&2 + } + + function http(){ + cat <<EOH + +$http_cfg__about + +A REST API Client with curl + +Enter http.help to show all commands. + +EOH + # $0 is not the current file if we source a script + # grep "function http.[a-z]" $0 | sort + } + + # ...................................................................... + # + # Initialize the client + # + # Initialize the client for a new request. Call this before any other + # function. It will reset all variables. + # + function http.init(){ + http._wd "${FUNCNAME[0]}()" + which curl >/dev/null || http.quit + + # request vars + + http_req__auth= + http_req__authorization= + http_req__accept="application/json" + http_req__headers=() + http_req__curlparams=() + + http_req__body= + http_req__method=GET + http_req__url= + http_req__fullurl= + http_req__docs= + http_req__cafile= + http_req__insecure= + + http_req__dataprefix="RESTAPICLIENTMETADATA_$(date +%s)_$$" + local writevar= + for myvar in $curlMeta + do + writevar="${writevar}|${myvar}:%{${myvar}}" + done + http_curl__writeout="\\n${http_req__dataprefix}${writevar}\\n" + + # cache + http_cfg__cacheTtl=0 + http_cfg__cacheFile= + + # response + http_resp__all= + http_resp__neutral= + mkdir ${http_cfg__cacheDir} 2>/dev/null + chmod 777 ${http_cfg__cacheDir} 2>/dev/null + } + + # ...................................................................... + # + # Execute the request + # + # param string optional: method; GET|POST|PUT|DELETE|... + # param string optional: full url + # param string optional: request body + # + # description: + # + # This function does the following: + # + # 1. Check if to use a cache + # 2. If not cached, make the request + # 3. If cached, use the cached result + # + function http.makeRequest(){ + http._wd "${FUNCNAME[0]}()" + + # --- handle optional prams + if [ $# -ne 0 ]; then + if echo "$1" | grep -q "^[A-Z]*$"; then + http.setMethod "$1" + shift 1 + fi + http.setUrl "$1" + http.setBody "$2" + fi + # test -z "$1" || http.setFullUrl "$1" + + # --- detect caching + local useCache=0 + local makeRequest=1 + 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") + if [ -f "${http_cfg__cacheFile}" ]; then + http.responseImport "${http_cfg__cacheFile}" + local iAge; typeset -i 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 ] && [ $iAge -lt $http_cfg__cacheTtl ]; then + http._wd "INFO: Using cache" + makeRequest=0 + else + http._wd "INFO: Cache file will be updated after making the request" + rm -f "${http_cfg__cacheFile}" 2>/dev/null + fi + fi + fi + + + # --- make the request + if [ $makeRequest -eq 1 ]; then + + # build curl parameters + local curl_params=( + -s + -i "${http_req__fullurl}" + -X "${http_req__method}" + -A "${http_cfg__UA}" + ) + test -n "$http_req__auth" && curl_params+=( -u "$http_req__auth" ) + test -n "$http_req__authorization" && curl_params+=( -H "Authorization: $http_req__authorization" ) + test -n "$http_req__accept" && curl_params+=( -H "Accept: $http_req__accept" ) + test -n "$http_req__body" && curl_params+=( -d "${http_req__body}" ) + test -n "$http_req__insecure" && curl_params+=( -k ) + test -n "$http_req__cafile" && curl_params+=( --cacert "$http_req__cafile" ) + curl_params+=( "${http_req__headers[@]}" ) + curl_params+=( "${http_req__curlparams[@]}" ) + + http._wd "${FUNCNAME[0]}($1) ${http_req__method} ${http_req__fullurl}" + http._wd "${FUNCNAME[0]}($1) ${curl_params[@]}" + curl_params+=( -w "${http_curl__writeout}" ) + + http_resp__all=$( curl "${curl_params[@]}") || http.quit + + http._wd "OK - Curl finished the http request ... processing data" + 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)" + } + + # ...................................................................... + # + # Show error message with last return code and quit with this exitcode + # + # This function is used to quit the script with a meaningful error message + # and the exit code of the last command. + # + # The message is printed to STDERR and contains the return code. + # If a documentation URL is known, it is printed as a hint. + # + # The exit code is the one of the last command. + # To prevent the script from exiting when this function is called from a + # sourced file, the exit is commented out. + # + # no params + # + function http.quit(){ + rc=$? + http._wd "${FUNCNAME[0]}()" + echo >&2 + echo -e "\e[31m# ERROR: command FAILED with rc $rc. \e[0m" >&2 + if [ ! -z "${RestApiDocs}" ]; then + echo "HINT: see ${RestApiDocs}" >&2 + fi + # dont make exit in a sourced file + # exit $rc + } + + + # ...................................................................... + # + # Load a config file + # + # This function is marked as deprecated. + # It will be removed in the future. + # + # param string config file name + # + # Sourcing that file will set the following vars + # - RestApiUser + # - RestApiPassword + # - RestApiBaseUrl + # - RestApiDocs + # + # The function will then set the "internal" vars + # - http_req__auth + # - http_req__fullurl + # - http_req__docs + # + function http.loadcfg(){ + http._wd "${FUNCNAME[0]}($1) !!! DEPRECATED !!!" + # reset expected vars from config + RestApiUser= + RestApiPassword= + RestApiBaseUrl= + RestApiDocs= + + # source config file + . "${1}" || http.quit + + # set "internal" vars + if [ -z "$RestApiPassword" ]; then + http.setAuth "$RestApiUser:$RestApiPassword" + else + http.setAuth + fi + http.setBaseUrl "${RestApiBaseUrl}" + http.setDocs "${RestApiDocs}" + } + + # ====================================================================== + # GETTER + # ====================================================================== + + # ...................................................................... + # + # Get the response header or response body + # + # param string what to return; one of header|body + # + # Return the response header or the response body. The output is the same + # as that of http.getResponseHeader or http.getResponse. The difference is + # the implementation + # + function http._fetchResponseHeaderOrBody(){ + http._wd "${FUNCNAME[0]}($1)" + local isheader=true + + # keep leading spaces + IFS='' + + echo "${http_resp__all}" | grep -v "${http_req__dataprefix}" | while read -r line; do + if $isheader; then + if [[ $line = $'\r' ]]; then + isheader=false + else + test "$1" = "header" && echo $line + fi + else + # body="$body"$'\n'"$line" + test "$1" = "body" && echo $line + fi + done + } + + # ...................................................................... + # + # Get the response data + # + # Return the curl meta infos like http_code, http_connect, local_ip, ... + # as key/ value pairs. Each line is a single key value pair. + # + # The data is extracted from the response header. The format is: + # ${http_req__dataprefix}|key|value|key|value|... + # + function http._fetchResponseData(){ + 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" + done + } + + # ...................................................................... + # + # Generate the dump with request and response + function http._fetchAllAndReformat(){ + http._wd "${FUNCNAME[0]}()" + IFS='' + line="#------------------------------------------------------------" + + echo "#_META_|about:$http_cfg__about" + 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_|body:$http_req__body" + echo "#_REQUEST_|baseurl:$http_req__baseurl" + echo "#_REQUEST_|url:$http_req__url" + echo "#_REQUEST_|docs:$http_req__docs" + echo $line + http._fetchResponseHeaderOrBody header | sed "s,^,#_HEADER_|,g" + echo $line + http._fetchResponseData | sed "s,^,#_DATA_|,g" + echo $line + http._fetchResponseHeaderOrBody body | sed "s,^,#_BODY_|,g" + echo $line END + } + + # ...................................................................... + # + # Get a section from dump data + # + # param string what to return; one of HEADER|DATA|BODY + # + # returns string the requested part of the response + # + function http._getFilteredResponse(){ + http._wd "${FUNCNAME[0]}($1)" + echo "${http_resp__neutral}" | grep "^#_${1}_|" | cut -f 2- -d "|" + } + + # ---------- PUBLIC REQUEST GETTER + + # ...................................................................... + # + # Get timestamp of the response as a Unix timestamp. + # + # no param + # + # returns string the timestamp of the response + # + function http.getRequestTs(){ + 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 + # + # no param + # + # returns integer age of the response in sec + # + function http.getRequestAge(){ + http._wd "${FUNCNAME[0]}()" + local iAge; typeset -i iAge + local iTs; typeset -i iTs + iTs=$( http.getRequestTs ) + iAge=$( date +%s )-${iTs} + echo "$iAge" + } + + # ---------- PUBLIC RESPONSE GETTER + + # ...................................................................... + # + # Get response body + # + # no param + # + # returns string the response body + # + function http.getResponse(){ + http._wd "${FUNCNAME[0]}()" + http._getFilteredResponse BODY + } + + # ...................................................................... + # + # Get curl data of this request with status, transferred bytes, speed, ... + # + # no param + # + # returns string the response data + # + function http.getResponseData(){ + http._wd "${FUNCNAME[0]}()" + http._getFilteredResponse DATA + } + + # ...................................................................... + # + # Get response header + # + # no param + # + # returns string the response header + # + function http.getResponseHeader(){ + http._wd "${FUNCNAME[0]}()" + http._getFilteredResponse HEADER + } + + # ...................................................................... + # + # Get raw response (not available after import) + # + # no params + # + # no param + # + function http.getResponseRaw(){ + http._wd "${FUNCNAME[0]}()" + echo "${http_resp__all}" + } + + # ...................................................................... + # + # Get Http status as string OK|Redirect|Error + # + # no params + # + function http.getStatus(){ + http._wd "${FUNCNAME[0]}($1)" + http.isOk >/dev/null && echo OK + http.isRedirect >/dev/null && echo Redirect + http.isError >/dev/null && echo Error + } + + # ...................................................................... + # + # Get Http status code of the request as 3 digit number + # + # no params + # + function http.getStatuscode(){ + http._wd "${FUNCNAME[0]}()" + http.getResponseData | grep "^http_code:" | cut -f 2 -d ":" + } + + # ...................................................................... + # + # Check: was response a 2xx status code? + # output is a statuscode if it matches ... or empty + # Additionally you can verify the return code + # + # $? -eq 0 means YES + # $? -ne 0 means NO + # + # no params + # + function http.isOk(){ + http._wd "${FUNCNAME[0]}()" + http.getStatuscode | grep '2[0-9][0-9]' + } + + # ...................................................................... + # + # Was the repsonse a redirect? + # + # no params + # + function http.isRedirect(){ + http._wd "${FUNCNAME[0]}()" + http.getStatuscode | grep '3[0-9][0-9]' + } + + # ...................................................................... + # + # Was the repsonse a client error (4xx or 5xx) + # + # no params + # + function http.isError(){ + http._wd "${FUNCNAME[0]}()" + http.getStatuscode | grep '[45][0-9][0-9]' + } + + # ...................................................................... + # + # Was the repsonse a client error (4xx) + # + # no params + # + function http.isClientError(){ + http._wd "${FUNCNAME[0]}()" + http.getStatuscode | grep '4[0-9][0-9]' + } + + # ...................................................................... + # + # Was the repsonse a client error (5xx) + # + # no params + # + function http.isServerError(){ + http._wd "${FUNCNAME[0]}()" + http.getStatuscode | grep '5[0-9][0-9]' + } + + # ...................................................................... + # + # Dump information about request and response + # + # no params + # + function http.dump(){ + http._wd "${FUNCNAME[0]}()" + http.responseExport + } + + # ====================================================================== + # Import/ Export + # ====================================================================== + + # ...................................................................... + # + # Helper to replace "AUTOFILE" with something uniq using full url + # + # param string import or export filename + # + function http._genOutfilename(){ + http._wd "${FUNCNAME[0]}($1)" + if echo "$1" | grep -q "AUTOFILE"; then + echo "$1" + else + 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 response to a file + # + # param string optional: custom filename + # + function http.responseExport(){ + http._wd "${FUNCNAME[0]}($1)" + if [ -z "$1" ]; then + echo "${http_resp__neutral}" + else + local outfile + outfile=$(http._genOutfilename "$1") + http._wd "${FUNCNAME[0]}($1) writing to outfile $outfile" + echo "${http_resp__neutral}" >"$outfile" + fi + } + + # ...................................................................... + # + # Import a former response from a file + # + # param string filename with stored response + # + function http.responseImport(){ + http._wd "${FUNCNAME[0]}($1)" + local infile + infile=$(http._genOutfilename "$1") + if [ -r "${infile}" ]; then + if grep -q "^#_META_|about:$http_cfg__about" "${infile}"; then + http_resp__neutral=$(cat "${infile}") + else + echo "ERROR: Ooops [${infile}] does not seem to be an export dump." + http.quit + fi + else + echo "ERROR: Ooops the file [${infile}] is not readable." + http.quit + fi + } + + # ...................................................................... + # + # Delete an exported file; this is especially useful if you use + # AUTOFILE functionality + # + # param string filename with stored response + # + function http.responseDelete(){ + http._wd "${FUNCNAME[0]}($1)" + local infile + infile=$(http._genOutfilename "$1") + if [ -r "${infile}" ]; then + if grep -q "^#_META_|about:$http_cfg__about" "${infile}"; then + if rm -f "${infile}"; then + http._wd "OK, ${infile} was deleted." + else + http._wd "ERROR: unable to delete existing ${infile}. Check permissions." + fi + else + http._wd "SKIP: ${infile} is not an export file." + fi + else + http._wd "SKIP: ${infile} is not readable." + fi + } + + # ====================================================================== + # SETTER + # ====================================================================== + + # ...................................................................... + # + # Add a line to the request header + # + # param string line to add, eg "Connection: keep-alive" + # + function http.addHeader(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__headers+=( -H "$1") + } + + # ...................................................................... + # + # Add an additional curl parameter + # + # param string line to add, eg "Connection: keep-alive" + # + function http.addCurlparam(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__curlparams+=( "$1") + } + + # ...................................................................... + # + # set Accept request header and override default + # + # param string accept header value, eg text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + # + function http.setAccept(){ + http._wd "${FUNCNAME[0]}($1)" + if [ -z "$1" ]; then + http_req__accept= + else + http_req__accept="$1" + fi + } + + # ...................................................................... + # + # Set basic authentication + # Without given parameter, authentication is removed + # + # param string optional: USER:PASSWORD + # + function http.setAuth(){ + http._wd "${FUNCNAME[0]}($1)" + if [ -z "$1" ]; then + http_req__auth= + else + http_req__auth="$1" + fi + } + + # ...................................................................... + # + # Set authentication via Athorization header + # Without given parameter, authorization is removed + # + # param string optional: type, eg. Basic|Bearer|Negotiate + # param string optional: token or encoded user + password + # + function http.setAuthorization(){ + http._wd "${FUNCNAME[0]}($1 $2)" + if [ -z "$1" ]; then + http_req__authorization= + else + http_req__authorization="${1} ${2}" + fi + } + + # ...................................................................... + # + # Set body to send for PUTs and POSTs + # + # param string body + # + function http.setBody(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__body=$1 + } + + # ...................................................................... + # + # Set a base url of an API + # Remark: Then use http.setUrl to complet the url to request + # + # param string url + # + function http.setBaseUrl(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__baseurl=$1 + http.setFullUrl "" + } + + # ...................................................................... + # + # set and unset CA cert file to use + # + # param string optional: filename to use; no value to disable cafile + # + function http.setCA(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__cafile="$1" + } + + # ...................................................................... + # + # Enable or disable debug mode + # + # param integer 0|1 + # + function http.setDebug(){ + http._wd "${FUNCNAME[0]}($1)" + http_cfg__debug=$1 + } + + + function http.setDocs(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__docs=$1 + } + # ...................................................................... + # + # Allow and disallow insecure connections + # + # param string optional: 1 to enable insecure flag; no value to disable insecure flag + # + function http.setInsecure(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__insecure="$1" + } + + # ...................................................................... + # + # Set the method to use; GET|POST|PUT|DELETE|... + # + # param string name of method + # + function http.setMethod(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__method=$1 + } + + # ...................................................................... + # + # Set a full url to request + # + # param string optional: url + # + function http.setFullUrl(){ + http._wd "${FUNCNAME[0]}($1)" + if [ -z "$1" ]; then + http_req__fullurl=${http_req__baseurl}${http_req__url} + else + http_req__fullurl=$1 + fi + } + + # ...................................................................... + # + # Complete the base url + # + # param string url part behind base url + # + function http.setUrl(){ + http._wd "${FUNCNAME[0]}($1)" + http_req__url=$1 + http.setFullUrl + } + + # ----- caching + + # ...................................................................... + # + # Set cache ttl in seconds + # + # param integer ttl in seconds + # + function http.setCacheTtl(){ + http._wd "${FUNCNAME[0]}($1)" + http_cfg__cacheTtl=$1 + } + + # ...................................................................... + # + # Set cache file + # + # param string filename + # + function http.setCacheFile(){ + http._wd "${FUNCNAME[0]}($1)" + http_cfg__cacheFile="$1" + } + + # ...................................................................... + # + # Flush the cache + # + # no params + # + function http.flushCache(){ + http._wd "${FUNCNAME[0]}($1)" + rm -f ${http_cfg__cacheDir}/* + } + + # ...................................................................... + # + # show a help text + # + # no params + # + function http.help(){ + cat <<EOH + +$http_cfg__about + +This is a bash solution to script REST API calls. + +Source: <$http_cfg__prjurl> +Docs: <$http_cfg__docsurl> +License: GNU GPL 3 + + +INSTRUCTION: + +- Source the file once +- Then you can run functions starting with "http." + + http.init + Start a new request. It resets internal vars of the last request + (if there was one). + + http.setDebug 0|1 + Enable or disable debugging infos during processing. It is written + to STDERR. + +- initialize a request + + setAccept "<ACCEPTHEADER>" + Set authentication with user and password for basic auth + Default: $http_req__accept + + setAuth "<USER>:<PASSWORD>" + Set authentication with user and password for basic auth + Without given parameter, authentication is removed + + setAuthorization "<TYPE>" "<TOKEN|HASH>" + Set authentication with Authorization header. + As TYPE you can use Basic|Bearer|Negotiate|... + 2nd param is the token or hashed user+password + Without given parameter, authorization is removed + + http.setBody "<DATA>" + set a body for POST/ PUT requests. + + http.setBaseUrl "<URL>" + Set a base url to an api. + renmark: + Use http.setUrl to built a complete url. + + http.setCA "<FILE>" + Set CA file to verify the server certificate. + Default: [empty] = use system defaults + Without parameter the cafile is removed + + http.setDocs "<URL>" + Set a docs url. If set it will be shown as additional hint when a + request fails. + + http.setInsecure 1 + Set insecure flag by giving any non empty value. + Default: [empty] = secure requests + Without parameter the insecure flag is removed + + http.setMethod "<METHOD>" + Set a http method. Use an uppercase string for GET|POST|PUT|DELETE|... + + http.setFullUrl "<URL>" + Set a complete url for a request. + + http.setUrl "<REQUEST?QUERY>" + Set a relative url for a request. + This requires to use http.setBaseUrl before. + + http.addHeader "<HEADER_LINE>" + Add a header line to the request. + This command can be repeated multiple times to add multiple headers. + + http.addCurlparam "<CURL_PARAMETER>" + Add any missing parameter for curl requestst. + This command can be repeated multiple times to add multiple prameters. + You also can add multiple parameters with one command. + +- caching functions + + http.setCacheTtl <SECONDS> + Enable caching with values > 0 + Remark: only GET requests will be cached. + Default: 0 (no caching) + + http.setCacheFile "<FILENAME>" + Set a file where to read/ store a request + Default: empty; autogenerated file below $http_cfg__cacheDir + + http.flushCache + Delete all files in $http_cfg__cacheDir + +- make the request + + http.makeRequest [[<METHOD>] ["<URL>"] ["<BODY>"]] + The parameters are optional. Without parameter the request will be + started with given data in http.set* functions described above. + If minimum one param is given then they are handled: + METHOD optional: set a method (must be uppercase) - see http.setMethod + URL set a relative url - see http.setUrl + BODY optional: set a body - see http.setBody + + The request will be skipped and uses a cached content if ... + - METHOD is GET + - http.setCacheTtl set a value > 0 + - the cache file exists and is younger than the given TTL + +- handle response + + http.getResponse + Get the Response Body + + http.getResponseData + Get Meta infos from curl + + http.getResponseHeader + Get The http reponse header + +- check http status code + + http.getStatus + Get the http status as string Ok|Redirect|Error + + http.getStatuscode + Get the http status code of a request as 3 digit integer + + http.isOk + Check if the http response code is a 2xx + + http.isRedirect + Check if the http response code is a 3xx + + http.isError + Check if the http response code is a 4xx or 5xx + + http.isClientError + Check if the http response code is a 4xx + + http.isServerError + Check if the http response code is a 5xx + + http.getRequestAge + Get the age of the request in seconds. + Remark: This function is useful after an import + see http.responseImport. + + http.getRequestTs + Get the Unix timestamp of the request + +- import/ export + + http.responseExport ["<FILE>"] + dump the response data + Without parameter it is written on STDOUT. + You can set a filename to write it to a file. + The filename can contain "AUTOFILE" this string + will be replaced with a uniq string. + (requires sha1sum and a set url) + Example: + http.makeRequest "https://example.com/api/" + http.responseExport /tmp/something_AUTOFILE_.txt + + http.responseImport "<FILE>" + Import an export file. + To use the AUTOFILE mechanism from export set + the url first. + Example: + http.setFullUrl "https://example.com/api/" + http.responseImport /tmp/something_AUTOFILE_.txt + + http.responseDelete "<FILE>" + Delete a file after http.responseExport. + It is useful if you use the AUTOFILE mechanism. + +EOH + } + +# ---------------------------------------------------------------------- +# +# main +# +# ---------------------------------------------------------------------- + + http.init + +# ---------------------------------------------------------------------- diff --git a/rest-api-client.sh b/rest-api-client.sh index 0ac9e9d0a66aedb0a7ea3eb973d33e90988245ae..b07340cae95f7208920d12545800d1e8188e9f4c 100644 --- a/rest-api-client.sh +++ b/rest-api-client.sh @@ -1,1027 +1,6 @@ #!/bin/bash -# ====================================================================== -# -# REST API CLIENT USING CURL -# -# REQUIREMENTS -# - Bash (Linux or MS Windows i.e with Cygwin) -# - curl -# - sha1sum (optional; for export functionality with AUTOFILE only) -# ---------------------------------------------------------------------- -# License: GPL 3.0 -# Source: <https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client> -# Docs: <https://os-docs.iml.unibe.ch/bash-rest-api-client/> -# ---------------------------------------------------------------------- -# (1) source this script -# (2) enter "http.help" to get a list of available commands -# ---------------------------------------------------------------------- -# 2020-02-07 v0.2 axel.hahn@iml.unibe.ch BETABETA -# 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 -# 2024-10-09 v0.8 axel.hahn@unibe.ch add setAuthorization; customize accept header, add custom request headers -# 2024-10-10 v0.9 axel.hahn@unibe.ch update docs -# 2024-10-23 v0.10 axel.hahn@unibe.ch update help -# ====================================================================== - http_cfg__about="Bash REST API client v0.10" - typeset -i http_cfg__debug=0 - typeset -i http_cfg__cacheTtl=0 - http_cfg__cacheDir=/var/tmp/http-cache - http_cfg__UA="${http_cfg__about}" - http_cfg__prjurl="https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client" - http_cfg__docsurl="https://os-docs.iml.unibe.ch/bash-rest-api-client/" +>&2 echo "DEPRECATED: Source 'http.class.sh' instead of 'rest-api-client.sh'" -# --- curl meta infos to collect -# see variables in man curl --write-out param - curlMeta="\ - http_code \ - http_connect \ - local_ip \ - local_port \ - num_connects \ - num_redirects \ - redirect_url \ - remote_ip \ - remote_port \ - size_download \ - size_header \ - size_request \ - size_upload \ - speed_download \ - speed_upload \ - ssl_verify_result \ - time_appconnect \ - time_connect \ - time_namelookup \ - time_pretransfer \ - time_redirect \ - time_starttransfer \ - time_total \ - url_effective \ -" - - -# ---------------------------------------------------------------------- -# -# functions -# -# ---------------------------------------------------------------------- - - # ...................................................................... - # - # Write a debug message to STDERR - # Do no not change the prefix - is is read in inc_functions - # - # params strings output message - # - function http._wd(){ - if [ $http_cfg__debug -gt 0 ]; then - echo -e "\e[33m# RESTAPI::DEBUG $*\e[0m" >&2 - fi - } - - # ...................................................................... - # - # Write an error message to STDERR - # Do no not change the prefix - is is read in inc_functions - # - # params strings output message - # - function http._we(){ - echo -e "\e[31m# RESTAPI::ERROR $*\e[0m" >&2 - } - - function http(){ - cat <<EOH - -$http_cfg__about - -A REST API Client with curl - -Enter http.help to show all commands. - -EOH - # $0 is not the current file if we source a script - # grep "function http.[a-z]" $0 | sort - } - - # ...................................................................... - # - # Initialize the client - # - # Initialize the client for a new request. Call this before any other - # function. It will reset all variables. - # - function http.init(){ - http._wd "${FUNCNAME[0]}()" - which curl >/dev/null || http.quit - - # request vars - - http_req__auth= - http_req__authorization= - http_req__accept="application/json" - http_req__headers=() - - http_req__body= - http_req__method=GET - http_req__url= - http_req__fullurl= - http_req__docs= - - http_req__dataprefix="RESTAPICLIENTMETADATA_$(date +%s)_$$" - local writevar= - for myvar in $curlMeta - do - writevar="${writevar}|${myvar}:%{${myvar}}" - done - http_curl__writeout="\\n${http_req__dataprefix}${writevar}\\n" - - # cache - http_cfg__cacheTtl=0 - http_cfg__cacheFile= - - # response - http_resp__all= - http_resp__neutral= - mkdir ${http_cfg__cacheDir} 2>/dev/null - chmod 777 ${http_cfg__cacheDir} 2>/dev/null - } - - # ...................................................................... - # - # Execute the request - # - # param string optional: method; GET|POST|PUT|DELETE|... - # param string optional: full url - # param string optional: request body - # - # description: - # - # This function does the following: - # - # 1. Check if to use a cache - # 2. If not cached, make the request - # 3. If cached, use the cached result - # - function http.makeRequest(){ - http._wd "${FUNCNAME[0]}()" - - # --- handle optional prams - if [ $# -ne 0 ]; then - if echo "$1" | grep -q "^[A-Z]*$"; then - http.setMethod "$1" - shift 1 - fi - http.setUrl "$1" - http.setBody "$2" - fi - # test -z "$1" || http.setFullUrl "$1" - - # --- detect caching - local useCache=0 - local makeRequest=1 - 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") - if [ -f "${http_cfg__cacheFile}" ]; then - http.responseImport "${http_cfg__cacheFile}" - local iAge; typeset -i 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 ] && [ $iAge -lt $http_cfg__cacheTtl ]; then - http._wd "INFO: Using cache" - makeRequest=0 - else - http._wd "INFO: Cache file will be updated after making the request" - rm -f "${http_cfg__cacheFile}" 2>/dev/null - fi - fi - fi - - - # --- make the request - if [ $makeRequest -eq 1 ]; then - - # build curl parameters - local curl_params=( - -k - -s - -i "${http_req__fullurl}" - -X "${http_req__method}" - -w "${http_curl__writeout}" - -A "${http_cfg__UA}" - ) - test -n "$http_req__auth" && curl_params+=( -u "$http_req__auth" ) - test -n "$http_req__authorization" && curl_params+=( -H "Authorization: $http_req__authorization" ) - test -n "$http_req__accept" && curl_params+=( -H "Accept: $http_req__accept" ) - test -n "$http_req__body" && curl_params+=( -d "${http_req__body}" ) - curl_params+=( "${http_req__headers[@]}" ) - - http._wd "${FUNCNAME[0]}($1) ${http_req__method} ${http_req__fullurl}" - http_resp__all=$( curl "${curl_params[@]}") || http.quit - - http._wd "OK - Curl finished the http request ... processing data" - 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)" - } - - # ...................................................................... - # - # Show error message with last return code and quit with this exitcode - # - # This function is used to quit the script with a meaningful error message - # and the exit code of the last command. - # - # The message is printed to STDERR and contains the return code. - # If a documentation URL is known, it is printed as a hint. - # - # The exit code is the one of the last command. - # To prevent the script from exiting when this function is called from a - # sourced file, the exit is commented out. - # - # no params - # - function http.quit(){ - rc=$? - http._wd "${FUNCNAME[0]}()" - echo >&2 - echo -e "\e[31m# ERROR: command FAILED with rc $rc. \e[0m" >&2 - if [ ! -z "${RestApiDocs}" ]; then - echo "HINT: see ${RestApiDocs}" >&2 - fi - # dont make exit in a sourced file - # exit $rc - } - - - # ...................................................................... - # - # Load a config file - # - # This function is marked as deprecated. - # It will be removed in the future. - # - # param string config file name - # - # Sourcing that file will set the following vars - # - RestApiUser - # - RestApiPassword - # - RestApiBaseUrl - # - RestApiDocs - # - # The function will then set the "internal" vars - # - http_req__auth - # - http_req__fullurl - # - http_req__docs - # - function http.loadcfg(){ - http._wd "${FUNCNAME[0]}($1) !!! DEPRECATED !!!" - # reset expected vars from config - RestApiUser= - RestApiPassword= - RestApiBaseUrl= - RestApiDocs= - - # source config file - . "${1}" || http.quit - - # set "internal" vars - if [ -z "$RestApiPassword" ]; then - http.setAuth "$RestApiUser:$RestApiPassword" - else - http.setAuth - fi - http.setBaseUrl "${RestApiBaseUrl}" - http.setDocs "${RestApiDocs}" - } - - # ====================================================================== - # GETTER - # ====================================================================== - - # ...................................................................... - # - # Get the response header or response body - # - # param string what to return; one of header|body - # - # Return the response header or the response body. The output is the same - # as that of http.getResponseHeader or http.getResponse. The difference is - # the implementation - # - function http._fetchResponseHeaderOrBody(){ - http._wd "${FUNCNAME[0]}($1)" - local isheader=true - - # keep leading spaces - IFS='' - - echo "${http_resp__all}" | grep -v "${http_req__dataprefix}" | while read -r line; do - if $isheader; then - if [[ $line = $'\r' ]]; then - isheader=false - else - test "$1" = "header" && echo $line - fi - else - # body="$body"$'\n'"$line" - test "$1" = "body" && echo $line - fi - done - } - - # ...................................................................... - # - # Get the response data - # - # Return the curl meta infos like http_code, http_connect, local_ip, ... - # as key/ value pairs. Each line is a single key value pair. - # - # The data is extracted from the response header. The format is: - # ${http_req__dataprefix}|key|value|key|value|... - # - function http._fetchResponseData(){ - 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" - done - } - - # ...................................................................... - # - # Generate the dump with request and response - function http._fetchAllAndReformat(){ - http._wd "${FUNCNAME[0]}()" - IFS='' - line="#------------------------------------------------------------" - - echo "#_META_|about:$http_cfg__about" - 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_|body:$http_req__body" - echo "#_REQUEST_|baseurl:$http_req__baseurl" - echo "#_REQUEST_|url:$http_req__url" - echo "#_REQUEST_|docs:$http_req__docs" - echo $line - http._fetchResponseHeaderOrBody header | sed "s,^,#_HEADER_|,g" - echo $line - http._fetchResponseData | sed "s,^,#_DATA_|,g" - echo $line - http._fetchResponseHeaderOrBody body | sed "s,^,#_BODY_|,g" - echo $line END - } - - # ...................................................................... - # - # Get a section from dump data - # - # param string what to return; one of HEADER|DATA|BODY - # - # returns string the requested part of the response - # - function http._getFilteredResponse(){ - http._wd "${FUNCNAME[0]}($1)" - echo "${http_resp__neutral}" | grep "^#_${1}_|" | cut -f 2- -d "|" - } - - # ---------- PUBLIC REQUEST GETTER - - # ...................................................................... - # - # Get timestamp of the response as a Unix timestamp. - # - # no param - # - # returns string the timestamp of the response - # - function http.getRequestTs(){ - 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 - # - # no param - # - # returns integer age of the response in sec - # - function http.getRequestAge(){ - http._wd "${FUNCNAME[0]}()" - local iAge; typeset -i iAge - local iTs; typeset -i iTs - iTs=$( http.getRequestTs ) - iAge=$( date +%s )-${iTs} - echo "$iAge" - } - - # ---------- PUBLIC RESPONSE GETTER - - # ...................................................................... - # - # Get response body - # - # no param - # - # returns string the response body - # - function http.getResponse(){ - http._wd "${FUNCNAME[0]}()" - http._getFilteredResponse BODY - } - - # ...................................................................... - # - # Get curl data of this request with status, transferred bytes, speed, ... - # - # no param - # - # returns string the response data - # - function http.getResponseData(){ - http._wd "${FUNCNAME[0]}()" - http._getFilteredResponse DATA - } - - # ...................................................................... - # - # Get response header - # - # no param - # - # returns string the response header - # - function http.getResponseHeader(){ - http._wd "${FUNCNAME[0]}()" - http._getFilteredResponse HEADER - } - - # ...................................................................... - # - # Get raw response (not available after import) - # - # no params - # - # no param - # - function http.getResponseRaw(){ - http._wd "${FUNCNAME[0]}()" - echo "${http_resp__all}" - } - - # ...................................................................... - # - # Get Http status as string OK|Redirect|Error - # - # no params - # - function http.getStatus(){ - http._wd "${FUNCNAME[0]}($1)" - http.isOk >/dev/null && echo OK - http.isRedirect >/dev/null && echo Redirect - http.isError >/dev/null && echo Error - } - - # ...................................................................... - # - # Get Http status code of the request as 3 digit number - # - # no params - # - function http.getStatuscode(){ - http._wd "${FUNCNAME[0]}()" - http.getResponseData | grep "^http_code:" | cut -f 2 -d ":" - } - - # ...................................................................... - # - # Check: was response a 2xx status code? - # output is a statuscode if it matches ... or empty - # Additionally you can verify the return code - # - # $? -eq 0 means YES - # $? -ne 0 means NO - # - # no params - # - function http.isOk(){ - http._wd "${FUNCNAME[0]}()" - http.getStatuscode | grep '2[0-9][0-9]' - } - - # ...................................................................... - # - # Was the repsonse a redirect? - # - # no params - # - function http.isRedirect(){ - http._wd "${FUNCNAME[0]}()" - http.getStatuscode | grep '3[0-9][0-9]' - } - - # ...................................................................... - # - # Was the repsonse a client error (4xx or 5xx) - # - # no params - # - function http.isError(){ - http._wd "${FUNCNAME[0]}()" - http.getStatuscode | grep '[45][0-9][0-9]' - } - - # ...................................................................... - # - # Was the repsonse a client error (4xx) - # - # no params - # - function http.isClientError(){ - http._wd "${FUNCNAME[0]}()" - http.getStatuscode | grep '4[0-9][0-9]' - } - - # ...................................................................... - # - # Was the repsonse a client error (5xx) - # - # no params - # - function http.isServerError(){ - http._wd "${FUNCNAME[0]}()" - http.getStatuscode | grep '5[0-9][0-9]' - } - - # ...................................................................... - # - # Dump information about request and response - # - # no params - # - function http.dump(){ - http._wd "${FUNCNAME[0]}()" - http.responseExport - } - - # ====================================================================== - # Import/ Export - # ====================================================================== - - # ...................................................................... - # - # Helper to replace "AUTOFILE" with something uniq using full url - # - # param string import or export filename - # - function http._genOutfilename(){ - http._wd "${FUNCNAME[0]}($1)" - if echo "$1" | grep -q "AUTOFILE"; then - echo "$1" - else - 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 response to a file - # - # param string optional: custom filename - # - function http.responseExport(){ - http._wd "${FUNCNAME[0]}($1)" - if [ -z "$1" ]; then - echo "${http_resp__neutral}" - else - local outfile - outfile=$(http._genOutfilename "$1") - http._wd "${FUNCNAME[0]}($1) writing to outfile $outfile" - echo "${http_resp__neutral}" >"$outfile" - fi - } - - # ...................................................................... - # - # Import a former response from a file - # - # param string filename with stored response - # - function http.responseImport(){ - http._wd "${FUNCNAME[0]}($1)" - local infile - infile=$(http._genOutfilename "$1") - if [ -r "${infile}" ]; then - if grep -q "^#_META_|about:$http_cfg__about" "${infile}"; then - http_resp__neutral=$(cat "${infile}") - else - echo "ERROR: Ooops [${infile}] does not seem to be an export dump." - http.quit - fi - else - echo "ERROR: Ooops the file [${infile}] is not readable." - http.quit - fi - } - - # ...................................................................... - # - # Delete an exported file; this is especially useful if you use - # AUTOFILE functionality - # - # param string filename with stored response - # - function http.responseDelete(){ - http._wd "${FUNCNAME[0]}($1)" - local infile - infile=$(http._genOutfilename "$1") - if [ -r "${infile}" ]; then - if grep -q "^#_META_|about:$http_cfg__about" "${infile}"; then - if rm -f "${infile}"; then - http._wd "OK, ${infile} was deleted." - else - http._wd "ERROR: unable to delete existing ${infile}. Check permissions." - fi - else - http._wd "SKIP: ${infile} is not an export file." - fi - else - http._wd "SKIP: ${infile} is not readable." - fi - } - - # ====================================================================== - # SETTER - # ====================================================================== - - # ...................................................................... - # - # Add a line to the request header - # - # param string line to add, eg "Connection: keep-alive" - # - function http.addHeader(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__headers+=( -H "$1") - } - - # ...................................................................... - # - # set Accept request header and override default - # - # param string accept header value, eg text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - # - function http.setAccept(){ - http._wd "${FUNCNAME[0]}($1)" - if [ -z "$1" ]; then - http_req__accept= - else - http_req__accept="$1" - fi - } - - # ...................................................................... - # - # Set basic authentication - # Without given parameter, authentication is removed - # - # param string optional: USER:PASSWORD - # - function http.setAuth(){ - http._wd "${FUNCNAME[0]}($1)" - if [ -z "$1" ]; then - http_req__auth= - else - http_req__auth="$1" - fi - } - - # ...................................................................... - # - # Set authentication via Athorization header - # Without given parameter, authorization is removed - # - # param string optional: type, eg. Basic|Bearer|Negotiate - # param string optional: token or encoded user + password - # - function http.setAuthorization(){ - http._wd "${FUNCNAME[0]}($1 $2)" - if [ -z "$1" ]; then - http_req__authorization= - else - http_req__authorization="${1} ${2}" - fi - } - - # ...................................................................... - # - # Set body to send for PUTs and POSTs - # - # param string body - # - function http.setBody(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__body=$1 - } - - # ...................................................................... - # - # Set a base url of an API - # Remark: Then use http.setUrl to complet the url to request - # - # param string url - # - function http.setBaseUrl(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__baseurl=$1 - http.setFullUrl "" - } - - # ...................................................................... - # - # Enable or disable debug mode - # - # param integer 0|1 - # - function http.setDebug(){ - http._wd "${FUNCNAME[0]}($1)" - http_cfg__debug=$1 - } - function http.setDocs(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__docs=$1 - } - - # ...................................................................... - # - # Set the method to use; GET|POST|PUT|DELETE|... - # - # param string name of method - # - function http.setMethod(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__method=$1 - } - - # ...................................................................... - # - # Set a full url to request - # - # param string optional: url - # - function http.setFullUrl(){ - http._wd "${FUNCNAME[0]}($1)" - if [ -z "$1" ]; then - http_req__fullurl=${http_req__baseurl}${http_req__url} - else - http_req__fullurl=$1 - fi - } - - # ...................................................................... - # - # Complete the base url - # - # param string url part behind base url - # - function http.setUrl(){ - http._wd "${FUNCNAME[0]}($1)" - http_req__url=$1 - http.setFullUrl - } - - # ----- caching - - # ...................................................................... - # - # Set cache ttl in seconds - # - # param integer ttl in seconds - # - function http.setCacheTtl(){ - http._wd "${FUNCNAME[0]}($1)" - http_cfg__cacheTtl=$1 - } - - # ...................................................................... - # - # Set cache file - # - # param string filename - # - function http.setCacheFile(){ - http._wd "${FUNCNAME[0]}($1)" - http_cfg__cacheFile="$1" - } - - # ...................................................................... - # - # Flush the cache - # - # no params - # - function http.flushCache(){ - http._wd "${FUNCNAME[0]}($1)" - rm -f ${http_cfg__cacheDir}/* - } - - # ...................................................................... - # - # show a help text - # - # no params - # - function http.help(){ - cat <<EOH - -$http_cfg__about - -This is a bash solution to script REST API calls. - -Source: <$http_cfg__prjurl> -Docs: <$http_cfg__docsurl> -License: GNU GPL 3 - - -INSTRUCTION: - -- Source the file once -- Then you can run functions starting with "http." - - http.init - Start a new request. It resets internal vars of the last request - (if there was one). - - http.setDebug 0|1 - Enable or disable debugging infos during processing. It is written - to STDERR. - -- initialize a request - - setAccept "<ACCEPTHEADER>" - Set authentication with user and password for basic auth - Default: $http_req__accept - - setAuth "<USER>:<PASSWORD>" - Set authentication with user and password for basic auth - Without given parameter, authentication is removed - - setAuthorization "<TYPE>" "<TOKEN|HASH>" - Set authentication with Authorization header. - As TYPE you can use Basic|Bearer|Negotiate|... - 2nd param is the token or hashed user+password - Without given parameter, authorization is removed - - http.setBody "<DATA>" - set a body for POST/ PUT requests. - - http.setBaseUrl "<URL>" - Set a base url to an api. - renmark: - Use http.setUrl to built a complete url. - - http.setDocs "<URL>" - Set a docs url. If set it will be shown as additional hint when a - request fails. - - http.setMethod "<METHOD>" - Set a http method. Use an uppercase string for GET|POST|PUT|DELETE|... - - http.setFullUrl "<URL>" - Set a complete url for a request. - - http.setUrl "<REQUEST?QUERY>" - Set a relative url for a request. - This requires to use http.setBaseUrl before. - - http.addHeader "<HEADER_LINE>" - Add a header line to the request. - This command can be repeated multiple times. - -- caching functions - - http.setCacheTtl <SECONDS> - Enable caching with values > 0 - Remark: only GET requests will be cached. - Default: 0 (no caching) - - http.setCacheFile "<FILENAME>" - Set a file where to read/ store a request - Default: empty; autogenerated file below $http_cfg__cacheDir - - http.flushCache - Delete all files in $http_cfg__cacheDir - -- make the request - - http.makeRequest [[<METHOD>] ["<URL>"] ["<BODY>"]] - The parameters are optional. Without parameter the request will be - started with given data in http.set* functions described above. - If minimum one param is given then they are handled: - METHOD optional: set a method (must be uppercase) - see http.setMethod - URL set a relative url - see http.setUrl - BODY optional: set a body - see http.setBody - - The request will be skipped and uses a cached content if ... - - METHOD is GET - - http.setCacheTtl set a value > 0 - - the cache file exists and is younger than the given TTL - -- handle response - - http.getResponse - Get the Response Body - - http.getResponseData - Get Meta infos from curl - - http.getResponseHeader - Get The http reponse header - -- check http status code - - http.getStatus - Get the http status as string Ok|Redirect|Error - - http.getStatuscode - Get the http status code of a request as 3 digit integer - - http.isOk - Check if the http response code is a 2xx - - http.isRedirect - Check if the http response code is a 3xx - - http.isError - Check if the http response code is a 4xx or 5xx - - http.isClientError - Check if the http response code is a 4xx - - http.isServerError - Check if the http response code is a 5xx - - http.getRequestAge - Get the age of the request in seconds. - Remark: This function is useful after an import - see http.responseImport. - - http.getRequestTs - Get the Unix timestamp of the request - -- import/ export - - http.responseExport ["<FILE>"] - dump the response data - Without parameter it is written on STDOUT. - You can set a filename to write it to a file. - The filename can contain "AUTOFILE" this string - will be replaced with a uniq string. - (requires sha1sum and a set url) - Example: - http.makeRequest "https://example.com/api/" - http.responseExport /tmp/something_AUTOFILE_.txt - - http.responseImport "<FILE>" - Import an export file. - To use the AUTOFILE mechanism from export set - the url first. - Example: - http.setFullUrl "https://example.com/api/" - http.responseImport /tmp/something_AUTOFILE_.txt - - http.responseDelete "<FILE>" - Delete a file after http.responseExport. - It is useful if you use the AUTOFILE mechanism. - -EOH - } - -# ---------------------------------------------------------------------- -# -# main -# -# ---------------------------------------------------------------------- - - http.init - -# ---------------------------------------------------------------------- +script_dir=$(dirname "$BASH_SOURCE[0]") +. "$script_dir/http.class.sh" $* diff --git a/scripts/generate_bash_docs.sh b/scripts/generate_bash_docs.sh index e353eee03650e1c99ac6ba5b5d1f634cbfd01974..f66dc422fec5e4ec1a7cab1d4ec467229da256ec 100755 --- a/scripts/generate_bash_docs.sh +++ b/scripts/generate_bash_docs.sh @@ -4,7 +4,7 @@ cd "$( dirname "$0" )" || exit BASHDOC=/home/axel/data/opensource/bash/bashdoc/bashdoc2md.sh -SOURCES=../rest-api-client.sh +SOURCES=../http.class.sh TARGETBASE=../docs/99_Functions REPO=https://git-repo.iml.unibe.ch/iml-open-source/bash-rest-api-client/-/blob/master/ diff --git a/tests/example_01_simple_get.sh b/tests/example_01_simple_get.sh index 4943e6c5decf841b1439ba861459766a2711fbb8..bc34490bfd7dd836a02b34c5d1f71a8dc8b778bc 100755 --- a/tests/example_01_simple_get.sh +++ b/tests/example_01_simple_get.sh @@ -11,7 +11,7 @@ cd "$( dirname "$0" )" || exit # shellcheck source=../rest-api-client.sh -. ../rest-api-client.sh +. ../http.class.sh # shellcheck source=color.class.sh . color.class.sh @@ -53,7 +53,7 @@ EOH color.reset -echo "We need to initialize the client with 'http.init' before each new request." +echo "We need to initialize the client with 'http.init' before a new request." echo color.echo "green" "> http.init" http.init