pashky / restclient.el

HTTP REST client tool for emacs
1.98k stars 161 forks source link

Bind response to a variable? #149

Open freckletonj opened 7 years ago

freckletonj commented 7 years ago

Especially, I'd like to POST .../login and parse out an auth token, which following endpoints require.

There's a way to do this with org-babel and ob-restclient, but that whole setup is a bit verbose, and not nearly as fun as just restclient.

PS, I have Postman PTSD, and I since I just discovered restclient I can begin to recover. Thank you!

freckletonj commented 7 years ago

Just leavin this here for anyone who might benefit, but a better option would still be appreciated:

I came up with this hack of a solution. It uses elisp to do the query instead of restclient, and then parses the header+body string into the token I want with some terrible, abysmal, abominable, evil, yet somehow elisp-appropriate hack.

:jwt := <<
(let ((url-request-method        "POST")
      (url-request-extra-headers '(("Content-Type" . "application/json")))
      (url-request-data          (json-encode '(("email" . "a") ("clearPass" . "a")))))
  (with-current-buffer (url-retrieve-synchronously "http://localhost:8081/token")
    (goto-char (point-min))
    (re-search-forward "\\\"")
    (delete-region (point) (point-min))
    (goto-char (point-max))
    (backward-char 1)
    (delete-region (point) (point-max))
    (buffer-string)))
#
FrancisMurillo commented 7 years ago

@freckletonj I think of advising the restclient-http-parse-current-and-do to wrap the callback function func to persist the arguments for the current request would suffice. Either way, this feature would be nice to have.

zachdaniel commented 6 years ago

Being able to do this would turn this tool from a great tool to a quintessential tool for me :)

TatriX commented 6 years ago

I ended up with the following:

(defvar my-restclient-token nil)
(defun my-restclient-hook ()
  "Update token from a request."
  (save-excursion
    (save-match-data
      ;; update regexp to extract required data
      (when (re-search-forward "\"token\":\"\\(.*?\\)\"" nil t)
        (setq my-restclient-token (match-string 1))))))

(add-hook 'restclient-response-received-hook #'my-restclient-hook)

and then in restclient

:token := my-restclient-token
...
GET http://127.0.0.1:3000/api/clients/
authorization: Token :token

So when you need to update a token you run your auth request

POST http://127.0.0.1:3000/api/users/login
Content-Type: application/json

{"user": {"login": "tester", "password": "qwerty"}}

and hook will extract the token for you, thus you can use it in your next requests.

TatriX commented 6 years ago

@pashky I think this feature is what a lot of users want, do you think this solution is good enough to be mentioned on the readme?

fibrasek commented 6 years ago

Is it possible to add conditional hooks? In my case, I have a consumer and user tokens that I need to retrieve from multiple URLs.

I know very basic elisp, if it's easy I can do a small PR for this.

Richard-Cranium commented 6 years ago

No, but the url is available in the hooks. You can switch actions based upon the url...

(require 'restclient)
(require 'json)

(defvar my-restclient-token nil)

(defun my-restclient-hook ()
  "Update token from a request."
  ;; url is visible while the hook is running.
  (let ((result))
    (save-excursion
      (cond
       ((string-suffix-p "/token" url)
    (condition-case nil
        (progn
          (setq result (cdr (assoc 'token (json-read)))
          (when (stringp result)
        (progn
          (setq my-restclient-token result)
          (message (concat "stored token: " my-restclient-token)))))
      (error (message "That wasn't cleanly handled."))))))))

(add-hook 'restclient-response-loaded-hook #'my-restclient-hook)
(provide 'restclient-hooks)

(The above assumes the response is json.)