federicotdn / verb

Organize and send HTTP requests from Emacs
https://melpa.org/#/verb
GNU General Public License v3.0
523 stars 21 forks source link

How to compute a field base on other fields? #28

Closed xuchunyang closed 3 years ago

xuchunyang commented 3 years ago

There is an API that requires the Authorization header to be computed at request time, it needs Method, URL and other Headers to compute Authorization, e.g.,

* List Buckets                                                         :verb:
GET https://cos.ap-shanghai.myqcloud.com/
Host: cos.ap-shanghai.myqcloud.com
Authorization: {{(cos5--sign "GET" "/" nil '(("Host" . "cos.ap-shanghai.myqcloud.com")))}}

but I do not want to fill the arguments by hand, It seems I can try (verb--request-spec-from-hierarchy) although it's a private function

(defun chunyang-verb-cos5-sign ()
  (pcase-let (((eieio method url headers)
               (save-excursion
                 (verb--request-spec-from-hierarchy))))
    (pcase-let ((`(,path . ,query) (url-path-and-query url)))
      (cos5--sign
       method
       path
       (and query (url-parse-query-string query))            
       (cl-remove "Authorization" headers
                  :key #'car
                  :test #'string=) ))))

but when I use it in verb, it reports

user-error: Lisp nesting exceeds `max-lisp-eval-depth'

which is not very surprise, it seems both I and verb try to compute Authorization. Any ideas?

* List Buckets                                                         :verb:
GET https://cos.ap-shanghai.myqcloud.com/
Host: cos.ap-shanghai.myqcloud.com
Authorization: {{ (chunyang-verb-cos5-sign) }}
federicotdn commented 3 years ago

It looks like this could be solved by applying a user-defined function right before the request is sent. Take a look here: https://github.com/federicotdn/verb/issues/25#issuecomment-645492662. Let me know if it helps!

xuchunyang commented 3 years ago

Great! It works for one heading, e.g.,

* List Buckets                                                         :verb:
:PROPERTIES:
:Verb-Map-Request: chunyang-verb-cos5-insert-authorization
:END:

GET https://service.cos.myqcloud.com/
(defun chunyang-verb-cos5-insert-authorization (request-spec)
  (pcase-let (((eieio method url headers) request-spec))
    (cl-assert (not (member "Authorization" headers)))
    (pcase-let ((`(,path . ,query) (url-path-and-query url)))
      (cl-callf2 cons
          (cons "Authorization" (cos5--sign method path query headers))
          (oref request-spec headers))
      request-spec)))

However, it does not inherit, right? e.g., this does not work

* COS                                                                  :verb:
:PROPERTIES:
:Verb-Map-Request: chunyang-verb-cos5-insert-authorization
:END:

** Service 接口
template https://service.cos.myqcloud.com

*** GET Service(List Buckets)
GET /

I've tried (setq org-use-property-inheritance t) but it does not help.

federicotdn commented 3 years ago

You are right, the property is not inherited. I thought org-entry-get would respect the value of org-use-property-inheritance but it doesn't by default, unless INHERIT is set to 'selective. I'll push a fix now.

federicotdn commented 3 years ago

Ok! I've pushed a commit to master. Once it's on MELPA you should be able to use org-use-property-inheritance set to t and make it work.

xuchunyang commented 3 years ago

Thanks. I'll try again after upgrade.

xuchunyang commented 3 years ago

Works perfectly.