[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] scratch/api.el be74f6a 4/4: * lisp/emacs-lisp/rest.el: Fin
From: |
Artur Malabarba |
Subject: |
[Emacs-diffs] scratch/api.el be74f6a 4/4: * lisp/emacs-lisp/rest.el: Finish renaming |
Date: |
Fri, 13 Nov 2015 15:08:41 +0000 |
branch: scratch/api.el
commit be74f6a7cffe3fc80604549da5d024652f63fd26
Author: Artur Malabarba <address@hidden>
Commit: Artur Malabarba <address@hidden>
* lisp/emacs-lisp/rest.el: Finish renaming
---
lisp/emacs-lisp/rest.el | 246 ++++++++++++++++++++++-------------------------
1 files changed, 116 insertions(+), 130 deletions(-)
diff --git a/lisp/emacs-lisp/rest.el b/lisp/emacs-lisp/rest.el
index 592836d..08408c6 100644
--- a/lisp/emacs-lisp/rest.el
+++ b/lisp/emacs-lisp/rest.el
@@ -1,6 +1,6 @@
-;;; api.el --- library for interacting with restful web APIs -*-
lexical-binding: t; -*-
+;;; rest.el --- library for interacting with restful web APIs -*-
lexical-binding: t; -*-
-;; Copyright (C) 2015 Artur Malabarba
+;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Author: Artur Malabarba <address@hidden>
;; Keywords: comm
@@ -28,7 +28,7 @@
;;; Error reporting
-(defun api-report-buffer ()
+(defun rest-report-buffer ()
"Write TEXT to the *Api Server* buffer."
(let ((text (buffer-string)))
(with-current-buffer (get-buffer-create "*Api Report*")
@@ -37,42 +37,42 @@
(insert text))
(goto-char (point-min)))))
-(define-error 'api-error "Unkown api error, see \"*Api Report*\" buffer")
-(define-error 'api-page-does-not-exist
+(define-error 'rest-error "Unkown REST error, see \"*Api Report*\" buffer")
+(define-error 'rest-page-does-not-exist
"This page doesn't seem to exist (see \"*Api Report*\" buffer), replied said"
- 'api-error)
-(define-error 'api-empty-redirect
+ 'rest-error)
+(define-error 'rest-empty-redirect
"Redirect received, but Location header not found! (see \"*Api Report*\"
buffer)"
- 'api-error)
-(define-error 'api-unintelligible-result
+ 'rest-error)
+(define-error 'rest-unintelligible-result
"Tried contacting server, but I can't understand the reply. See \"*Api
Report*\" buffer"
- 'api-error)
-(define-error 'api-bad-request
+ 'rest-error)
+(define-error 'rest-bad-request
"Server didn't understand my request, please you should probably file a bug
report"
- 'api-error)
-(define-error 'api-unauthorized
+ 'rest-error)
+(define-error 'rest-unauthorized
"Server says you're not authenticated"
- 'api-error)
-(define-error 'api-infinite-redirection-loop
+ 'rest-error)
+(define-error 'rest-infinite-redirection-loop
"Server is sending us in a redirection loop"
- 'api-error)
-(define-error 'api-server-error
+ 'rest-error)
+(define-error 'rest-server-error
"Something bad happened on the server side, see \"*Api Report*\" buffer"
- 'api-error)
+ 'rest-error)
-(defun api-error (signal &rest args)
+(defun rest-error (signal &rest args)
"Throw an error SIGNAL with ARGS.
Also print contents of current buffer to *Api Report*."
(declare (indent 1))
- (api-report-buffer)
+ (rest-report-buffer)
(signal signal args))
-(defun api-parse-response-code (&optional is-auth)
+(defun rest-parse-response-code (&optional is-auth)
"Non-nil if this reponse buffer looks ok.
Leave point at the return code on the first line."
(goto-char (point-min))
(unless (search-forward-regexp "^HTTP/[.0-9]+ +" nil t)
- (api-error 'api-unintelligible-result))
+ (rest-error 'rest-unintelligible-result))
(pcase (thing-at-point 'number)
((or 100 204) nil) ;; OK, but no content.
((or 200 202 201 203) t) ;; OK, with content.
@@ -80,40 +80,31 @@ Leave point at the return code on the first line."
((or 301 302 303 304 305 307)
(if (search-forward-regexp "^Location: *\\([^\s\n\r\t]+\\)" nil 'noerror)
(match-string 1)
- (api-error 'api-empty-redirect)))
+ (rest-error 'rest-empty-redirect)))
;; Client errors
- ((or 403 404 405 410) (api-error 'api-page-does-not-exist
- (substring-no-properties (thing-at-point 'line) 0
-1)))
- ((or 400 422 408 409 411 412 413 414 415 416 417) (api-error
'api-bad-request))
- ((or 401 407) (api-error 'api-unauthorized
- (if is-auth "try creating a new token"
- "you probably need to configure a token")))
- ((pred (<= 500)) (api-error 'api-server-error))
- (_ (api-error 'api-error
- (substring (thing-at-point 'line) 0 -1)))))
+ ((or 403 404 405 410) (rest-error 'rest-page-does-not-exist
+ (substring-no-properties (thing-at-point
'line) 0 -1)))
+ ((or 400 422 408 409 411 412 413 414 415 416 417) (rest-error
'rest-bad-request))
+ ((or 401 407) (rest-error 'rest-unauthorized
+ (if is-auth "try creating a new token"
+ "you probably need to configure a token")))
+ ((pred (<= 500)) (rest-error 'rest-server-error))
+ (_ (rest-error 'rest-error
+ (substring (thing-at-point 'line) 0 -1)))))
;;; Requests
-(autoload 'auth-source-search "auth-source")
-(cl-defmacro api--with-server-buffer (method url &rest body &key async
unwind-form
- extra-headers &allow-other-keys)
+(cl-defmacro rest--with-response-buffer (method url &rest body &key async
unwind-form
+ extra-headers
&allow-other-keys)
"Run BODY in a Server request buffer.
UNWIND-FORM is run no matter what, and doesn't affect the return
value."
(declare (indent 2)
(debug t))
- (let ((call-name (make-symbol "callback"))
- (secret (make-symbol "secret")))
+ (let ((call-name (make-symbol "callback")))
(while (keywordp (car body))
(setq body (cdr (cdr body))))
- `(let ((,secret (when ,auth
- (if (listp ,auth)
- (or (car-safe (apply #'auth-source-search
- :require '(:secret) :max 1
- ,auth))
- (user-error "This request requires
authentication"))
- (lambda () ,auth))))
- (,call-name (lambda (status)
+ `(let ((,call-name (lambda (status)
(unwind-protect
(progn (when-let ((er (plist-get status :error)))
(error "Error retrieving: %s %S" ,url
er))
@@ -138,10 +129,10 @@ value."
(with-current-buffer buffer
(funcall ,call-name nil))))))))
-(defvar-local api-root nil
- "Prepended to api method when a full url is not given.")
+(defvar-local rest-url-root nil
+ "Prepended to REST url when a full url is not given.")
-(defun api--headers-alist ()
+(defun rest--headers-alist ()
"Return an alist of all headers above point."
(let ((ac))
(while (search-backward-regexp "^\\(X-[^ ]+\\): *\\(.*?\\)\r?$" nil
'noerror)
@@ -149,64 +140,59 @@ value."
ac))
ac))
-(autoload 'json-read "json")
-
-(defvar api--url-depth nil
- "Used to detect infinite redirection loops.")
-
;;; Authentication
-(defun api--auth-source-search (url-obj)
+(autoload 'auth-source-search "auth-source")
+(defun rest--auth-source-search (url-obj)
"Return authentication information for URL-OBJ.
URL-OBJ is a value returned by `url-generic-parse-url'.
Information is found by running `auth-source-search' with the
properties of URL-OBJ."
- (let ((type (url-type url-obj))
- (port (url-port url-obj))
+ (let ((port (url-port url-obj))
(args (list :require '(:secret) :host (url-host url-obj)
:max 1 :user (url-user url-obj))))
- (car (or (apply #'auth-source-search :port port :type type args)
- (apply #'auth-source-search :port port args)
+ (car (or (apply #'auth-source-search :port port args)
;; If URL does not specify a port, try again without the default.
(unless (url-portspec url-obj)
- (or (apply #'auth-source-search :type type args)
- (apply #'auth-source-search args)))))))
+ (or (apply #'auth-source-search args)))))))
-(defun api--get-auth-info (info)
+(defun rest--get-auth-info (info)
"Return a function that returns (USER . PASSWORD).
INFO is a plist returned by `auth-source-search'."
(let ((user (plist-get info :user))
(pass (plist-get info :secret)))
(lambda () (cons user (funcall pass)))))
-(defun api--make-authorization-header (_plist user password)
+(defun rest--make-authorization-header (_plist user password)
"Return an alist containing an \"Authorization\" header.
The car of the list is nil, so this function can be used as the
-AUTH-METHOD in `api-action'."
+AUTH-METHOD in `rest-action'."
`(nil . (("Authorization" . ,(concat "Basic "
(base64-encode-string
(concat user ":" password)))))))
;;; The function
+(autoload 'json-read "json")
+
;;;###autoload
-(cl-defun api-action (url &rest all-options
- &key auth
- (method :get)
- (reader #'json-read)
- (callback #'identity)
- async
- (max-pages 1)
- (next-page-rule '(header "Link"))
- extra-headers
- (auth-method (if auth
#'api--make-authorization-header))
- (return :simple)
- -url-history)
+(cl-defun rest-action (url &rest all-options
+ &key auth
+ (method :get)
+ (reader #'json-read)
+ (callback #'identity)
+ async
+ (max-pages 1)
+ (next-page-rule '(header "Link"))
+ extra-headers
+ (auth-method (if auth
#'rest--make-authorization-header))
+ (return :simple)
+ -url-history)
"Contact URL with METHOD.
METHOD is a keyword of an http method, defaulting to :get.
URL can be a string such as \"user/starred?per_page=100\" to
-be appended at the end of `api-root'. It can also be a full url
+be appended at the end of `rest-url-root'. It can also be a full url
string, in which case it is used verbatim.
READER is called as a function with no arguments, with point
@@ -245,7 +231,7 @@ replaces URL and the cdr is appended to EXTRA-HEADERS. It
is
called with a plist, the user string and the password string.
The plist contais at least :url, :method, and :extra-headers.
-`api-action' can also handle the pagination used in server
+`rest-action' can also handle the pagination used in server
results by appending together the contents of each page. Use
MAX-PAGES to increase the number of pages that are
fetched (default 1).
@@ -263,25 +249,25 @@ values (string), as per `url-request-extra-headers'.
If the http request is unsuccessful, an error is signaled
according to the reply. The possible errors are:
-`api-bad-request', `api-server-error', `api-unauthorized',
-`api-unintelligible-result', `api-empty-redirect',
-`api-page-does-not-exist', and `api-infinite-redirection-loop',
-all of which inherit from `api-error'.
+`rest-bad-request', `rest-server-error', `rest-unauthorized',
+`rest-unintelligible-result', `rest-empty-redirect',
+`rest-page-does-not-exist', and `rest-infinite-redirection-loop',
+all of which inherit from `rest-error'.
\(fn URL &key AUTH (METHOD :get) (READER #'json-read) CALLBACK ASYNC
AUTH-METHOD (MAX-PAGES 1) NEXT-PAGE-RULE EXTRA-HEADERS RETURN)"
(declare (indent 1))
(unless (string-match "\\`https?://" url)
- (setq url (concat api-root url)))
+ (setq url (concat rest-url-root url)))
(when (member url -url-history)
- (signal 'api-infinite-redirection-loop (cons url api--url-depth)))
+ (signal 'rest-infinite-redirection-loop (cons url -url-history)))
(when auth
(let ((href (url-generic-parse-url url)))
(when (url-password href)
(error "AUTH requested, but URL already contains a password"))
(unless (functionp auth)
- (setq auth (api--get-auth-info (if (listp auth)
- (apply #'auth-source-search auth)
- (api--auth-source-search href)))))
+ (setq auth (rest--get-auth-info (if (listp auth)
+ (apply #'auth-source-search auth)
+ (rest--auth-source-search href)))))
(pcase-let* ((`(,user . ,pass) (funcall auth))
(`(,new-url . ,headers)
(funcall auth-method (list :url url :method method
@@ -289,47 +275,47 @@ all of which inherit from `api-error'.
user pass)))
(when new-url (setq url new-url))
(setq extra-headers (append headers extra-headers)))))
- (api--with-server-buffer method url
- :extra-headers extra-headers
- :-url-depth (cons url -url-history)
- :async async
- (pcase (api-parse-response-code auth)
- (`nil nil)
- ((and (pred stringp) link)
- (message "Redirected to %s" link)
- (apply #'api-action all-options))
- (`t
- (let ((next-page
- (when (pcase next-page-rule
- (`(header ,name) (search-forward-regexp
- (format "^%s: .*<\\([^>]+\\)>;"
(regexp-quote name))
- nil t))
- (`(regexp ,rx) (search-forward-regexp rx nil t))
- (_ nil))
- (match-string-no-properties 1))))
- (goto-char (point-min))
- (search-forward-regexp "^\r?$")
- (let* ((data (unless (eobp) (funcall reader))))
- (if (or (not next-page)
- (< max-pages 2))
- (pcase return
- (:simple (funcall callback data))
- (:rich `(,(funcall callback data)
- (next-page . ,next-page)
- ,@(api--headers-alist))))
- (api-action next-page
- :auth auth
- :method method
- :reader reader
- :next-page-rule next-page-rule
- :return return
- :async async
- :max-pages (1- max-pages)
- :callback (lambda (res)
- (funcall callback
- (if (listp res)
- (append data res)
- (vconcat data res))))))))))))
-
-(provide 'api)
-;;; api.el ends here
+ (rest--with-response-buffer method url
+ :extra-headers extra-headers
+ :-url-depth (cons url -url-history)
+ :async async
+ (pcase (rest-parse-response-code auth)
+ (`nil nil)
+ ((and (pred stringp) link)
+ (message "Redirected to %s" link)
+ (apply #'rest-action all-options))
+ (`t
+ (let ((next-page
+ (when (pcase next-page-rule
+ (`(header ,name)
(search-forward-regexp
+ (format
"^%s: .*<\\([^>]+\\)>;" (regexp-quote name))
+ nil t))
+ (`(regexp ,rx)
(search-forward-regexp rx nil t))
+ (_ nil))
+ (match-string-no-properties 1))))
+ (goto-char (point-min))
+ (search-forward-regexp "^\r?$")
+ (let* ((data (unless (eobp) (funcall
reader))))
+ (if (or (not next-page)
+ (< max-pages 2))
+ (pcase return
+ (:simple (funcall callback data))
+ (:rich `(,(funcall callback data)
+ (next-page . ,next-page)
+ ,@(rest--headers-alist))))
+ (rest-action next-page
+ :auth auth
+ :method method
+ :reader reader
+ :next-page-rule
next-page-rule
+ :return return
+ :async async
+ :max-pages (1- max-pages)
+ :callback (lambda (res)
+ (funcall
callback
+ (if
(listp res)
+
(append data res)
+
(vconcat data res))))))))))))
+
+(provide 'rest)
+;;; rest.el ends here