plz 
- Description
- HTTP library
- Latest
- plz-0.9.1.tar (.sig), 2024-Aug-17, 200 KiB
- Maintainer
- Adam Porter <adam@alphapapa.net>
- Website
- https://github.com/alphapapa/plz.el
- Browse ELPA's repository
- CGit or Gitweb
- Badge
- Manual
- plz
To install this package from Emacs, use package-install or list-packages.
Full description
plz is an HTTP library for Emacs. It uses curl as a backend, which avoids some of the issues with using Emacs's built-in url library. It supports both synchronous and asynchronous requests. Its API is intended to be simple, natural, and expressive. Its code is intended to be simple and well-organized. Every feature is tested against httpbin.
1. Installation
1.1. GNU ELPA
plz is available in GNU ELPA. It may be installed in Emacs using the package-install command.
1.2. Manual
plz has no dependencies other than Emacs and curl. It's known to work on Emacs 26.3 or later. To install it manually, simply place plz.el in your load-path and (require 'plz).
2. Usage
The main public function is plz, which sends an HTTP request and returns either the result of the specified type (for a synchronous request), or the curl process object (for asynchronous requests). For asynchronous requests, callback, error-handling, and finalizer functions may be specified, as well as various other options.
2.1. Examples
Synchronously GET a URL and return the response body as a decoded string (here, raw JSON):
(plz 'get "https://httpbin.org/user-agent")
"{\n \"user-agent\": \"curl/7.35.0\"\n}\n"
Synchronously GET a URL that returns a JSON object, and parse and return it as an alist:
(plz 'get "https://httpbin.org/get" :as #'json-read)
((args) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Host . "httpbin.org") (User-Agent . "curl/7.35.0")) (url . "https://httpbin.org/get"))
Asynchronously POST a JSON object in the request body, then parse a JSON object from the response body, and call a function with the result:
(plz 'post "https://httpbin.org/post"
:headers '(("Content-Type" . "application/json"))
:body (json-encode '(("key" . "value")))
:as #'json-read
:then (lambda (alist)
(message "Result: %s" (alist-get 'data alist))))
Result: {"key":"value"}
Synchronously download a JPEG file, then create an Emacs image object from the data:
(let ((jpeg-data (plz 'get "https://httpbin.org/image/jpeg" :as 'binary))) (create-image jpeg-data nil 'data))
(image :type jpeg :data ""ÿØÿà^@^PJFIF...")
2.2. Functions
plz(method url &key headers body else finally noquery (as 'string) (then 'sync) (body-type 'text) (decode t decode-s) (connect-timeout plz-connect-timeout) (timeout plz-timeout))
Request
METHODfromURLwith curl. Return the curl process object or, for a synchronous request, the selected result.HEADERSmay be an alist of extra headers to send with the request.BODYmay be a string, a buffer, or a list like(file FILENAME)to upload a file from disk.BODY-TYPEmay betextto sendBODYas text, orbinaryto send it as binary.ASselects the kind of result to pass to the callback functionTHEN, or the kind of result to return for synchronous requests. It may be:bufferto pass the response buffer, which will be narrowed to the response body and decoded according toDECODE.binaryto pass the response body as an un-decoded string.stringto pass the response body as a decoded string.responseto pass aplz-responsestructure.fileto pass a temporary filename to which the response body has been saved without decoding.(file ~FILENAME)to passFILENAMEafter having saved the response body to it without decoding.FILENAMEmust be a non-existent file; if it exists, it will not be overwritten, and an error will be signaled.FILENAMEis passed throughexpand-file-name, which see.- A function, which is called in the response buffer with it narrowed to the response body (suitable for, e.g.
json-read).
If
DECODEis non-nil, the response body is decoded automatically. For binary content, it should be nil. WhenASisbinary,DECODEis automatically set to nil.THENis a callback function, whose sole argument is selected above withAS; if the request fails and noELSEfunction is given (see below), the argument will be aplz-errorstructure describing the error. OrTHENmay besyncto make a synchronous request, in which case the result is returned directly from this function.ELSEis an optional callback function called when the request fails (i.e. if curl fails, or if theHTTPresponse has a non-2xx status code). It is called with one argument, aplz-errorstructure. IfELSEis nil, aplz-curl-errororplz-http-erroris signaled when the request fails, with aplz-errorstructure as the error data. For synchronous requests, this argument is ignored.NOTE: In v0.8 ofplz, only one error will be signaled:plz-error. The existing errors,plz-curl-errorandplz-http-error, inherit fromplz-errorto allow applications to update their code while using v0.7 (i.e. anycondition-caseforms should now handle onlyplz-error, not the other two).FINALLYis an optional function called without argument afterTHENorELSE, as appropriate. For synchronous requests, this argument is ignored.CONNECT-TIMEOUTandTIMEOUTare a number of seconds that limit how long it takes to connect to a host and to receive a response from a host, respectively.NOQUERYis passed tomake-process, which see.FILTERis an optional function to be used as the process filter for the curl process. It can be used to handle HTTP responses in a streaming way. The function must accept 2 arguments, the process object running curl, and a string which is output received from the process. The default process filter inserts the output of the process into the process buffer. The providedFILTERfunction should at least insert output up to the HTTP body into the process buffer.
2.3. Queueing
plz provides a simple system for queueing HTTP requests. First, make a plz-queue struct by calling make-plz-queue. Then call plz-queue with the struct as the first argument, and the rest of the arguments being the same as those passed to plz. Then call plz-run to run the queued requests.
All of the queue-related functions return the queue as their value, making them easy to use. For example:
(defvar my-queue (make-plz-queue :limit 2)) (plz-run (plz-queue my-queue 'get "https://httpbin.org/get?foo=0" :then (lambda (body) (message "%s" body))))
Or:
(let ((queue (make-plz-queue :limit 2
:finally (lambda ()
(message "Queue empty."))))
(urls '("https://httpbin.org/get?foo=0"
"https://httpbin.org/get?foo=1")))
(plz-run
(dolist (url urls queue)
(plz-queue queue 'get url
:then (lambda (body) (message "%s" body))))))
You may also clear a queue with plz-clear, which cancels any active or queued requests and calls their :else functions. And plz-length returns the number of a queue's active and queued requests.
2.4. Tips
- You can customize settings in the
plzgroup, but this can only be used to adjust a few defaults. It's not intended that changing or binding global variables be necessary for normal operation.
3. Changelog
3.1. 0.9.1
Fixes
- Expand filenames when downloading to files (which was already applied to filenames passed for uploading). (Thanks to Joseph Turner.)
3.2. 0.9
Compatibility
- The minimum supported Emacs version is now 27.1. (It is no longer practical to test
plzwith Emacs versions older than 27.1. For Emacs 26.3, an earlier version ofplzmay be used, or this version might be compatible, with or without minor changes, which the maintainer cannot offer support for.)
Changes
- Option
plz-timeoutis removed. (It was the default value forplz's:timeoutargument, which is passed to Curl as its--max-timeargument, limiting the total duration of a request operation. This argument should be unset by default, because larger or slower downloads might not finish within a certain duration, and it is surprising to the user to have this option set by default, potentially causing requests to timeout unnecessarily.) - Using arguments
:as 'fileor:as '(file FILENAME)now passes the filename to Curl, allowing it to write the data to the file itself (rather than receiving the data into an Emacs buffer and then writing it to a file. This improves performance when downloading large files, significantly reducing Emacs's CPU and memory usage).
Fixes
- Improve workaround for Emacs's process sentinel-related issues. (Don't try to process response a second time if Emacs calls the sentinel after
plzhas returned for a synchronous request. See #53. Thanks to Joseph Turner for extensive help debugging, and to USHIN for sponsoring some of this work.) - Inhibit buffer hooks when calling
generate-new-buffer(as extra protection against "kill buffer?" prompts in case of errors). (See #52. Thanks to Michał Krzywkowski.)- Avoid "kill buffer?" prompts in case of errors on Emacs versions before 28. (See #52 and #57. Thanks to Michał Krzywkowski.)
Development
plzis now automatically tested against Emacs versions 27.1, 27.2, 28.1, 28.2, 29.1, 29.2, 29.3, and a recent snapshot of themasterbranch (adding 29.2 and 29.3).
3.3. 0.8
Additions
- Function
plznow accepts a:filterargument which can be used to override the default process filter (e.g. for streaming responses). (#43, #50. Thanks to Roman Scherer.)
3.4. 0.7.3
Fixes
- Info manual generation on GNU ELPA. (Also, the Info manual is no longer committed to Git.)
3.5. 0.7.2
Fixes
- Don't delete preexisting files when downloading to a file. (#41. Thanks to Joseph Turner.)
3.6. 0.7.1
Fixes
- Handle HTTP 303 redirects. (Thanks to Daniel Hubmann for reporting.)
3.7. 0.7
Changes
A new error signal,
plz-error, is defined. The existing signals,plz-curl-errorandplz-http-error, inherit from it, so handlingplz-errorcatches both.NOTE: The existing signals,
plz-curl-errorandplz-http-error, are hereby deprecated, and they will be removed in v0.8. Applications should be updated while using v0.7 to only expectplz-error.
Fixes
- Significant improvement in reliability by implementing failsafes and workarounds for Emacs's process-handling code. (See #3.)
- STDERR output from curl processes is not included in response bodies (which sometimes happened, depending on Emacs's internal race conditions). (Fixes #23.)
- Use
with-local-quitfor synchronous requests (preventing Emacs from complaining sometimes). (Fixes #26.) - Various fixes for
:as 'bufferresult type: decode body when appropriate; unset multibyte for binary; narrow to body; don't kill buffer prematurely. - When clearing a queue, don't try to kill finished processes.
Internal
- Response processing now happens outside the process sentinel, so any errors (e.g. in user callbacks) are not signaled from inside the sentinel. (This avoids the 2-second pause Emacs imposes in such cases.)
- Tests run against a local instance of httpbin (since the
httpbin.orgserver is often overloaded). - No buffer-local variables are defined anymore; process properties are used instead.
3.8. 0.6
Additions
- Function
plz's:bodyargument now accepts a list like(file FILENAME)to upload a file from disk (by passing the filename to curl, rather than reading its content into Emacs and sending it to curl through the pipe).
Fixes
- Function
plz's docstring now mentions that the:bodyargument may also be a buffer (an intentional feature that was accidentally undocumented). - Handle HTTP 3xx redirects when using
:as 'response.
3.9. 0.5.4
Fixes
- Only run queue's
finallyfunction after queue is empty. (New features should not be designed and released on a Friday.)
3.10. 0.5.3
Fixes
- Move new slot in
plz-queuestruct to end to prevent invalid byte-compiler expansions for already-compiled applications (which would require them to be recompiled after upgradingplz).
3.11. 0.5.2
Fixes
- When clearing a queue, only call
plz-queue'sfinallyfunction when specified.
3.12. 0.5.1
Fixes
- Only call
plz-queue'sfinallyfunction when specified. (Thanks to Dan Oriani for reporting.)
3.13. 0.5
Additions
- Struct
plz-queue'sfinallyslot, a function called when the queue is finished.
3.14. 0.4
Additions
- Support for HTTP
HEADrequests. (Thanks to USHIN for sponsoring.)
Changes
- Allow sending
POSTandPUTrequests without bodies. (#16. Thanks to Joseph Turner for reporting. Thanks to USHIN for sponsoring.)
Fixes
- All 2xx HTTP status codes are considered successful. (#17. Thanks to Joseph Turner for reporting. Thanks to USHIN for sponsoring.)
- Errors are signaled with error data correctly.
Internal
- Test suite explicitly tests with both HTTP/1.1 and HTTP/2.
- Test suite also tests with Emacs versions 27.2, 28.1, and 28.2.
3.15. 0.3
Additions
- Handle HTTP proxy headers from Curl. (#2. Thanks to Alan Third and Sawyer Zheng for reporting.)
Fixes
- Replaced words not in Ispell's default dictionaries (so
checkdoclinting succeeds).
3.16. 0.2.1
Fixes
- Handle when Curl process is interrupted.
3.17. 0.2
Added
- Simple request queueing.
3.18. 0.1
Initial release.
4. Credits
- Thanks to Chris Wellons, author of the Elfeed feed reader and the popular blog null program, for his invaluable advice, review, and encouragement.
5. Development
Bug reports, feature requests, suggestions — oh my!
Note that plz is a young library, and its only client so far is Ement.el. There are a variety of HTTP and curl features it does not yet support, since they have not been needed by the author. Patches are welcome, as long as they include passing tests.
5.1. Copyright assignment
This package is part of GNU Emacs, being distributed in GNU ELPA. Contributions to this project must follow GNU guidelines, which means that, as with other parts of Emacs, patches of more than a few lines must be accompanied by having assigned copyright for the contribution to the FSF. Contributors who wish to do so may contact emacs-devel@gnu.org to request the assignment form.
6. License
GPLv3
Old versions
| plz-0.9.tar.lz | 2024-Jun-10 | 76.2 KiB |
| plz-0.8.tar.lz | 2024-Apr-26 | 73.8 KiB |
| plz-0.7.3.tar.lz | 2024-Mar-31 | 74.0 KiB |
| plz-0.7.2.tar.lz | 2024-Jan-14 | 74.0 KiB |
| plz-0.7.1.tar.lz | 2023-Dec-18 | 73.8 KiB |
| plz-0.7.tar.lz | 2023-Jul-09 | 73.8 KiB |
| plz-0.6.tar.lz | 2023-Jun-14 | 71.4 KiB |
| plz-0.5.4.tar.lz | 2023-Apr-16 | 70.7 KiB |
| plz-0.5.tar.lz | 2023-Apr-14 | 70.1 KiB |
| plz-0.4.tar.lz | 2023-Mar-17 | 70.0 KiB |
| plz-0.3.tar.lz | 2022-Dec-31 | 68.3 KiB |
| plz-0.2.1.tar.lz | 2022-Sep-26 | 67.8 KiB |
| plz-0.2.tar.lz | 2022-Jul-17 | 67.5 KiB |
| plz-0.1.tar.lz | 2022-May-12 | 64.6 KiB |