Function: verb-request-spec-from-string
verb-request-spec-from-string is a natively compiled function defined
in verb.el.
Signature
(verb-request-spec-from-string TEXT &optional METADATA)
Documentation
Create and return a request specification from string TEXT.
The text format for request specifications is the following:
[COMMENT]...
METHOD [URL]
[HEADER]...
[BODY]
Each COMMENT must start with "#" or ":" (see Org mode comments and headline property syntax). All comments will be discarded after being read (they are not part of the returned value). COMMENT may also be a blank line.
METHOD must be a method matched by verb--http-methods-regexp (that
is, an HTTP method or the value of verb--template-keyword).
Matching is case-insensitive.
URL must be a full URL, or a part of it. If present, the scheme must be "http" or "https". If the scheme is not present, the URL will be interpreted as a path, plus (if present) query string and fragment. Therefore, using just "example.org" (note no scheme present) as URL will result in a URL with its path set to "example.org", not as its host. URL may end in a backslash, in which case the following line will be appended to it (ignoring its leading whitespace). The process is repeated as long as the current line ends with a backslash.
Each HEADER must be in the form of KEY: VALUE. KEY must be a nonempty
string, VALUE can be the empty string. HEADER may also start with
"#", in which case it will be ignored.
BODY can contain arbitrary data. Note that there must be a blank line between the HEADER list and BODY. If BODY contains a properly formatted Babel source block, the block beginning and end lines will be removed.
As a special case, if the text specification consists exclusively of
comments and/or whitespace, or is the empty string, signal
verb-empty-spec.
If TEXT does not conform to the request specification text format, signal an error.
Before returning the request specification, set its metadata to METADATA.
Source Code
;; Defined in /nix/store/8jnfn8w2mxcxbr2crbklcnija9m0zlkq-emacs-packages-deps/share/emacs/site-lisp/elpa/verb-20260818.1921/verb.el
(defun verb-request-spec-from-string (text &optional metadata)
"Create and return a request specification from string TEXT.
The text format for request specifications is the following:
[COMMENT]...
METHOD [URL]
[HEADER]...
[BODY]
Each COMMENT must start with \"#\" or \":\" (see Org mode comments and
headline property syntax). All comments will be discarded after being
read (they are not part of the returned value). COMMENT may also be a
blank line.
METHOD must be a method matched by `verb--http-methods-regexp' (that
is, an HTTP method or the value of `verb--template-keyword').
Matching is case-insensitive.
URL must be a full URL, or a part of it. If present, the scheme must
be \"http\" or \"https\". If the scheme is not present, the URL will
be interpreted as a path, plus (if present) query string and fragment.
Therefore, using just \"example.org\" (note no scheme present) as URL
will result in a URL with its path set to \"example.org\", not as its
host. URL may end in a backslash, in which case the following line
will be appended to it (ignoring its leading whitespace). The process
is repeated as long as the current line ends with a backslash.
Each HEADER must be in the form of KEY: VALUE. KEY must be a nonempty
string, VALUE can be the empty string. HEADER may also start with
\"#\", in which case it will be ignored.
BODY can contain arbitrary data. Note that there must be a blank
line between the HEADER list and BODY. If BODY contains a properly
formatted Babel source block, the block beginning and end lines will
be removed.
As a special case, if the text specification consists exclusively of
comments and/or whitespace, or is the empty string, signal
`verb-empty-spec'.
If TEXT does not conform to the request specification text format,
signal an error.
Before returning the request specification, set its metadata to
METADATA."
(let ((context (current-buffer))
method url headers headers-start body backslash)
(with-temp-buffer
(insert text)
(goto-char (point-min))
;;; COMMENTS + PROPERTIES
;; Skip initial blank lines, comments and properties.
(while (and (re-search-forward "^\\s-*\\(\\(:\\|#\\).*\\)?$"
(line-end-position) t)
(not (eobp)))
(forward-char))
;; Check if the entire specification was just comments or empty.
(when (string-empty-p (string-trim (buffer-substring (point)
(point-max))))
;; Signal `verb-empty-spec' if so
(signal 'verb-empty-spec nil))
;;; METHOD + URL
;; Read HTTP method and URL line.
;; First, expand any code tags on it (if any):
(let* ((case-fold-search t)
(get-line-fn (lambda ()
(verb--eval-code-tags-in-string
(buffer-substring-no-properties
(point) (line-end-position))
context)))
(line (funcall get-line-fn)))
;; Try to match:
;; A) METHOD URL
;; B) METHOD
(if (string-match (concat "^\\s-*\\("
(verb--http-methods-regexp)
"\\)\\s-+\\(.+\\)$")
line)
;; A) Matched method + URL, store them.
(progn
(setq method (upcase (match-string 1 line))
url (string-remove-suffix "\\" (match-string 2 line)))
;; Subcase:
;; If URL ends with '\', append following lines to it
;; until one of them does not end with '\' (ignoring
;; leading whitespace, for alignment).
(while (string-suffix-p "\\" line)
(end-of-line)
(if (eobp)
(user-error
"Backslash in URL not followed by additional line")
(forward-char))
(back-to-indentation)
(setq line (funcall get-line-fn))
(when (string-empty-p line)
(user-error
"Backslash in URL not followed by additional content"))
(setq backslash t)
(setq url (concat url (string-remove-suffix "\\" line)))))
(when (string-match (concat "^\\s-*\\("
(verb--http-methods-regexp)
"\\)\\s-*$")
line)
;; B) Matched method only, store it.
(setq method (upcase (match-string 1 line))))))
;; We've processed the URL line, move to the end of it.
(end-of-line)
(if method
(when (string= method verb--template-keyword)
(setq method nil))
(user-error (concat "Could not read a valid HTTP method (%s)\n"
"Additionally, you can also specify %s "
"(matching is case insensitive)")
(mapconcat #'identity verb--http-methods ", ")
verb--template-keyword))
;; Skip newline after URL line.
(unless (eobp) (forward-char))
(setq headers-start (point))
;;; HEADERS
;; Scan forward until we find a blank line (headers end). In
;; the region covered, delete all lines starting with '#', as
;; these headers have been commented out. Finally, go back to
;; where we started.
(save-excursion
(while (re-search-forward "^.+$" (line-end-position) t)
(unless (eobp) (forward-char)))
(delete-matching-lines "^[[:blank:]]*#" headers-start (point)))
;; Expand code tags in the rest of the buffer (if any).
(save-excursion
(verb--eval-code-tags-in-buffer (current-buffer) context))
;; Parse HTTP headers, stop as soon as we find a blank line.
(while (re-search-forward "^\\(.+\\)$" (line-end-position) t)
(let ((line (match-string 1)))
;; Check if line matches KEY: VALUE.
(if (string-match verb-util--http-header-parse-regexp line)
;; Line matches, trim KEY and VALUE and store them.
(push (cons (string-trim (match-string 1 line))
(string-trim (match-string 2 line)))
headers)
(let ((msg (concat "Invalid HTTP header: \"%s\"\n"
"Make sure there's a blank line between"
" the headers and the request body")))
(when (and backslash (string-match-p "^\\s-+" line))
(setq msg (concat msg " (did you forget a backslash '\\'?)")))
(user-error msg line))))
(unless (eobp) (forward-char)))
(setq headers (nreverse headers))
;;; BODY
;; Allow users to include Babel source blocks in their request
;; bodies. This allows them to have font locking and other
;; features that depend on specific content types (e.g JSON,
;; XML, etc.). Here we delete the source block delimiters so
;; that they are not included in the actual request.
(delete-matching-lines "^[[:blank:]]*#\\+\\(begin\\|end\\)_src")
;; Skip blank line after headers.
(unless (eobp) (forward-char))
;; The rest of the buffer is the request body.
(let ((rest (buffer-substring (point) (point-max))))
;; Only read body if it isn't comprised entirely of
;; whitespace, but if it's not and has leading/trailing
;; whitespace, include it.
(unless (string-empty-p (string-trim rest))
;; Now we know body isn't comprised entirely of whitespace,
;; check if the user wants to delete any trailing characters.
(setq body (if verb-trim-body-end
(replace-regexp-in-string
(concat verb-trim-body-end "$") "" rest)
rest))))
(when (buffer-local-value 'verb--multipart-boundary context)
(verb-util--log nil 'W "Detected an unfinished multipart form"))
;; Return a `verb-request-spec'.
(verb-request-spec :method method
:url (unless (string-empty-p (or url ""))
(verb--clean-url url))
:headers headers
:body body
:metadata metadata))))