For a long time, my API development workflow lived inside Emacs — specifically
in a carefully maintained api.org
file spanning nearly 2,000 lines. Each
endpoint had a dedicated section, annotated and structured using org-mode
and
restclient.el
. It was efficient,
flexible, and tightly integrated with my editor.
But recently, that file has become… redundant.
While Emacs remains my daily driver for note-taking, planning, and writing, the
VS Code REST Client extension
has quietly replaced the need for a dedicated .org
file for API calls.
For example, where I used to write this in Emacs:
#+BEGIN_SRC restclient
POST http://localhost:3000/v1/something
Content-Type: application/json
{
"name": "testing something"
}
#+END_SRC
I now write this:
### @name createSomething
POST http://localhost:3000/v1/something
Content-Type: application/json
{
"name": "testing something"
}
The response can then be reused in subsequent requests using its id — no
scripting or postprocessing with jq
needed. In Emacs, this might have looked
like:
#+name: get_something_id
#+begin_src restclient :results value :jq-args -r :jq .[0].id
GET http://localhost:3000/v1/something
#+end_src
#+begin_src restclient :var something_id=get_something_id
GET http://localhost:3000/v1/something/:something_id
#+end_src
But in REST Client:
### @name createSomething
POST http://localhost:3000/v1/something
Content-Type: application/json
{
"name": "testing something"
}
### Get something by ID
GET http://localhost:3000/v1/something/{{createSomething.response.body.$.id}}
One unexpected benefit of this switch is how much easier it is to share
endpoints with others on the team — especially since not everyone uses the same
tools. These .http
files work well across workflows, and can even be embedded
as http
code blocks in Markdown to mimic the “living documentation” feel of an
org
file.
It’s not a replacement for ‘org-mode’ — but for API workflows, it’s a simpler, more portable alternative that gets out of the way.
Bonus Example: File Uploads
One thing I really disliked in my old setup was having to mix restclient
and
shell
blocks just to upload a file. For example:
#+begin_src shell :var something_id=(org-sbe get_something_id)
curl -F "file=@./something.jpeg" \
"http://localhost:3000/v1/something/:something_id/files"
#+end_src
Using REST Client, I can now write the same thing in a single .http
file:
### Upload file
POST http://localhost:3000/v1/something/{{createSomething.response.body.$.id}}/files
Content-Type: multipart/form-data; boundary=--FileUpload
----FileUpload
Content-Disposition: form-data; name="something"; filename="2194889204.jpeg"
Content-Type: image/jpeg
< ./something.jpeg
----FileUpload--
Note: According to
RFC 2046 Section 5.1.1,
multipart boundaries must start with --
. Easy to overlook when writing by
hand.