diff options
-rwxr-xr-x | rest-run | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/rest-run b/rest-run new file mode 100755 index 0000000..2a682ca --- /dev/null +++ b/rest-run @@ -0,0 +1,259 @@ +#!/bin/bash + +# me=$(basename $0) +me=rest-run + +# [ Helper functions + +print-help () { + echo "$me - call REST APIs like a goat of the pest, JJ's style" + echo + cat <<HELP +Usage: + cat /tmp/body.json | $me http://localhost:8080/api/path --body stdin + $me PUT http://localhost:8080/api/resource + +Positional arguments: + You must provide the API URL. An HTTP verb preceding it is accepted if present. + +Options: + -b|--body Request body source, must be one of the following options: + default - create a request body using the default editor + last - use the last request + history - pick from the request history + stdin - reads from piped input + -r|--response Request response handling, must be one of the following options: + default - store the request on cache + last - read last request, skip request + history - pick from the response history, skip request + -ne|--no-edit Skip request editting. Ignored when --body is set to default + -h|--header Header string. Ex: "Authorization: Bearer 123" + -p|--paginate Paginate request response + +rest-run parses your request body with a simple template engine called esh. +You can embed shell scripts/commands in your request file surrouning it +with <% my-command %> + +Example: + echo '{ + "created_at": "<% date +"%FT%T.000Z" %>" + }' +HELP +} + +fail () { + echo "$1 +" >&2 + print-help + exit 1 +} + +opt-fail () { + fail "Argument for $1 is missing" +} + +opt-validation-fail () { + fail "Value for option $1 is invalid" +} + +extract-url-domain () { + echo "$1" | sed 's/[a-z]*:\/\///g' | sed 's/\/.*//g' | sed 's/\?.*//g' +} + +remove-newlines-from-templates () { + sed 's/%>/ | xargs echo -n %>/g' +} + +# ] <- end helper functions + +# [ Check installed dependencies + +if ! command -v http > /dev/null; then + fail "You need HTTPie Client installed." +fi + +if ! command -v ranger > /dev/null; then + fail "You need Ranger File Manager installed." +fi + +if ! command -v sha1sum > /dev/null; then + fail "You need sha1sum command installed" +fi + +if ! command -v esh > /dev/null; then + fail "You need esh template engine installed." +fi + +# ] + +# [ Variable and script parameter definition + +CACHE_DIR="$HOME/.cache/rest-run/" +CACHE_DIR_CONTEXT="$CACHE_DIR" + +PARAMS="" + +rest_request_file="" +rest_response_file="" +rest_url="" +rest_method="POST" +rest_body="default" +rest_body_options=("default" "last" "stdin" "history") +rest_response="default" +rest_response_options=("default" "history" "last") +last_request_file="" +last_request_file_checksum="" +is_new_request=true +edit_rest_request=true +paginate_response=false +ignore_body=false +declare -a rest_headers=() + +# ] <- end variable definition + +# [ Arg parsing + +while (( "$#" )); do + case "$1" in + -ne|--no-edit) edit_rest_request=false && shift;; + -p|--paginate) paginate_response=true && shift;; + --help) print-help && exit;; + -b|--body) [[ -n "$2" && ${2:0:1} != "-" ]] && rest_body=$2 && shift 2 || opt-fail $1 ;; + -r|--response) [[ -n "$2" && ${2:0:1} != "-" ]] && rest_response=$2 && shift 2 || opt-fail $1 ;; + -h|--header) [[ -n "$2" && ${2:0:1} != "-" ]] && rest_headers+=("$2") && shift 2 || opt-fail $1 ;; + -*|--*=) fail "Unkown option $1" ;; + *) PARAMS="$PARAMS $1" && shift ;; + esac +done + +eval set -- "$PARAMS" + +IFS=' ' read -r -a ARGS <<< "$PARAMS" + +# ] <- end arg parsing + +# [ Arg validation + +! [[ " ${rest_body_options[*]} " =~ "$rest_body" ]] && opt-validation-fail "-b|--body" +! [[ " ${rest_response_options[*]} " =~ "$rest_response" ]] && opt-validation-fail "-r|--response" + +if [[ ${#ARGS[@]} -gt 1 ]]; then + rest_method="${ARGS[0]}" + case "$rest_method" in + POST|post);; + GET|get);; + PUT|put);; + PATCH|patch);; + DELETE|delete);; + *) fail "Invalid HTTP Verb $rest_method" ;; + esac + unset 'ARGS[0]' +fi + +[[ -z "$PARAMS" || "${#PARAMS}" = "1" ]] && fail "Not enough params" + +rest_url="${ARGS[*]}" +CACHE_DIR_CONTEXT="${CACHE_DIR_CONTEXT}$(extract-url-domain "$rest_url")" +CACHE_DIR_CONTEXT_RESPONSE="${CACHE_DIR_CONTEXT}/response" +CACHE_DIR_CONTEXT_REQUEST="${CACHE_DIR_CONTEXT}/request" + +mkdir -p "$CACHE_DIR_CONTEXT_RESPONSE" > /dev/null +mkdir -p "$CACHE_DIR_CONTEXT_REQUEST" > /dev/null + +rest_timestamp="$(date +"%s")" +rest_request_file="$CACHE_DIR_CONTEXT_REQUEST/request-$rest_timestamp.json" +last_request_file="$(find "$CACHE_DIR_CONTEXT_REQUEST" -type f | sort -n | tail -1)" +rest_response_file="$CACHE_DIR_CONTEXT_RESPONSE/response-$rest_timestamp.log" + +if ! [[ -z "$last_request_file" || "${#last_request_file}" = "0" ]]; then + last_request_file_checksum="$(cat "$last_request_file" | sha1sum | awk '{print $1}')" +fi + +if [[ "$rest_method" = "GET" || "$rest_method" = "get" ]]; then + ignore_body=true +fi + +# ] <- end arg validation + +# [ rest-run! + +case "$rest_response" in + last) + [ $paginate_response = true ] \ + && find "$CACHE_DIR_CONTEXT_RESPONSE" | sort -n | tail -1 | xargs less -r -f \ + || find "$CACHE_DIR_CONTEXT_RESPONSE" | sort -n | tail -1 | xargs cat + exit + ;; + history) + tmp_file="/tmp/choose-file-$$" + ranger --choosefile "$tmp_file" "$CACHE_DIR_CONTEXT_RESPONSE" + [[ "$(cat "$tmp_file" 2> /dev/null)" = "" ]] && fail "No file selected" + [ $paginate_response = true ] \ + && cat "$(cat "$tmp_file")" | less -r -f \ + || cat "$(cat "$tmp_file")" + rm "$tmp_file" + exit + ;; +esac + +if [ $ignore_body = false ]; then + case "$rest_body" in + last) + [[ -z "$last_request_file" || "${#last_request_file}" = "0" ]] && fail "No requests previously made" + cp "$(find "$CACHE_DIR_CONTEXT_REQUEST" | sort -n | tail -1)" "$rest_request_file" + ;; + history) + [[ -z "$last_request_file" || "${#last_request_file}" = "0" ]] && fail "No requests previously made" + tmp_file="/tmp/choose-file-$$" + ranger --choosefile "$tmp_file" "$CACHE_DIR_CONTEXT_REQUEST" + [[ "$(cat "$tmp_file" 2> /dev/null)" = "" ]] && fail "No file selected" + cp "$(cat "$tmp_file")" "$rest_request_file" + rm "$tmp_file" + ;; + stdin) + cat - > "$rest_request_file" + ;; + esac + + if [[ $edit_rest_request = true || "$rest_body" = "default" ]]; then + $EDITOR "$rest_request_file" + fi + +fi + +if [ $ignore_body = false ]; then # Send request body + + if [ $paginate_response = true ]; then + cat "$rest_request_file" \ + | remove-newlines-from-templates \ + | esh - \ + | eval -- http --pretty=all -p HBhbm \ + "$rest_method" \"$rest_url\" $(for h in "${rest_headers[@]}"; do echo \"$h\"; done) > "$rest_response_file" + less -r -f "$rest_response_file" + else + cat "$rest_request_file" \ + | remove-newlines-from-templates \ + | esh - \ + | eval -- http -p HBhbm \ + "$rest_method" \"$rest_url\" $(for h in "${rest_headers[@]}"; do echo \"$h\"; done) + fi + + current_request_checksum="$(cat "$rest_request_file" | sha1sum | awk '{print $1}')" + if [[ "${#current_request_checksum}" != "0" && "${#current_request_checksum}" != "1" ]]; then + if [[ "$current_request_checksum" = "$last_request_file_checksum" ]]; then + rm "$rest_request_file" + fi + fi + +else # Send request without body + + if [ $paginate_response = true ]; then + eval -- http --pretty=all -p HBhbm "$rest_method" \"$rest_url\" $(for h in "${rest_headers[@]}"; do echo \"$h\"; done) > "$rest_response_file" + less -r -f "$rest_response_file" + else + eval -- http -p HBhbm "$rest_method" \"$rest_url\" $(for h in "${rest_headers[@]}"; do echo \"$h\"; done) > "$rest_response_file" + fi + +fi + +# ] <- script end |