Published

All published posts

2565 posts latest post 2026-07-13 simple view
Publishing rhythm
Jun 2026 | 27 posts
I came across nvim-macroni [1] from jesseleite [2], and it’s packed with great features and ideas. 🤌 Save your macros for future use References: [1]: https://github.com/jesseleite/nvim-macroni [2]: https://github.com/jesseleite
jesseleite [1] has done a fantastic job with macroni.nvim [2]. Highly recommend taking a look. Save your macros for future use 🤌 References: [1]: https://github.com/jesseleite [2]: https://github.com/jesseleite/macroni.nvim
ikalnytskyi [1] has done a fantastic job with httpie-auth-store [2]. Highly recommend taking a look. Credential store plugin for HTTPie, attaches auth to ongoing request. References: [1]: https://github.com/ikalnytskyi [2]: https://github.com/ikalnytskyi/httpie-auth-store

Authentication from cli tools can be a bit of a bear, and I have to look it up every time. This is my reference guide for future me to remember how to easily do it.

I set up a fastapi server running on port 8000, it uses a basic auth with waylonwalker as the username and asdf as the password. The server follows along with what comes out of the docs. I have it setup to take basic auth, form username and password, or a bearer token for authentication.

curl #

The og of command line url tools.

# basic auth
curl -u 'waylonwalker:asdf' -X POST localhost:8000/token
# basic auth with password prompt
curl -u 'waylonwalker' -X POST localhost:8000/token
# token
curl -H 'Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YXlsb253YWxrZXIiLCJleHAiOjE3MDI5NTI2MDJ9.GeYNt7DNal6LTiPoavJnqypaMt4vYeriXdq5lqu1ILg' -X POST localhost:8000/token

wget #

My go to if I want the result to go into a file.

# basic auth
wget -q -O - --auth-no-challenge --http-user=waylonwalker --http-password=asdf --post-data '' localhost:8000/token

# token
wget -q -O - --header="Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YXlsb253YWxrZXIiLCJleHAiOjE3MDI5NTI2MDJ9.GeYNt7DNal6LTiPoavJnqypaMt4vYeriXdq5lqu1ILg" -O - --post-data '' localhost:8000/token

httpx #

An http client written in python, primarilty used with the python api, but has a nice cli.

# install
python3 -m pip install httpx

# basic auth
httpx -m POST --auth waylonwalker asdf http://localhost:8000/token

# basic auth with password prompt
httpx -m POST --auth waylonwalker - http://localhost:8000/token

# token
httpx -m POST --headers="Authorization" "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YXlsb253YWxrZXIiLCJleHAiOjE3MDI5NTI2MDJ9.GeYNt7DNal6LTiPoavJnqypaMt4vYeriXdq5lqu1ILg" http://localhost:8000/token

httpie #

A modern http client written in python.

# install
python3 -m pip install httpie

# basic auth
http POST localhost:8000/token -a waylonwalker:asdf

# basic auth with password prompt
http POST localhost:8000/token -a waylonwalker

# token
http POST localhost:8000/token -A bearer -a eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YXlsb253YWxrZXIiLCJleHAiOjE3MDI5NTI2MDJ9.GeYNt7DNal6LTiPoavJnqypaMt4vYeriXdq5lqu1ILg

httpie with plugin #

# install
python3 -m pip install httpie-credential-store
# usage
http POST localhost:8000/token -A creds

httpie prompt #

http-prompt comes from the httpie org, and has an interactive cli interface into apis. You can even specify a spec file to autocomplete on api methods.

http-prompt localhost:8000 --auth waylonwalker:asdf --spec openapi.json
External Link stackoverflow.com [1] After struggling to get dependencies inside of middleware I learned that you can make global dependencies at the app level. I used this to set the user on every single route of the application without needing Depend on getting the user on each route. from fastapi import Depends, FastAPI, Request def get_db_session(): print("Calling 'get_db_session(...)'") return "Some Value" def get_current_user(session=Depends(get_db_session)): print("Calling 'get_current_user(...)'") return session def recalculate_resources(request: Request, current_user=Depends(get_current_user)): print("calling 'recalculate_resources(...)'") request.state.foo = current_user app = FastAPI(dependencies=[Depends(recalculate_resources)]) @app.get("/") async def root(request: Request): return {"foo_from_dependency": request.state.foo} References: [1]: https://stackoverflow.com/questions/72243379/fastapi-dependency-inside-middleware#answer-72480781
Handling Errors - FastAPI FastAPI framework, high performance, easy to learn, fast to code, ready for production fastapi.tiangolo.com [1] This page shows how to customize your fastapi [2] errors. I found this very useful to setup common templates so that I can return the same 404’s both programatically and by default, so it all looks the same to the end user. from fastapi import FastAPI, Request from fastapi.responses import JSONResponse class UnicornException(Exception): def __init__(self, name: str): self.name = name app = FastAPI() @app.exception_handler(UnicornException) async def unicorn_exception_handler(request: Request, exc: UnicornException): return JSONResponse( status_code=418, content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, ) @app.get("/unicorns/{name}") async def read_unicorn(name: str): if name == "yolo": raise UnicornException(name=name) return {"unicorn_name": name} References: [1]: https://fastapi.tiangolo.com/tutorial/handling-errors/ [2]: /fastapi/
logs with FastAPI and Uvicorn · Issue #1508 · fastapi/fastapi Hello, Thanks for FastAPI, easy to use in my Python projects ! However, I have an issue with logs. In my Python project, I use : app = FastAPI() uvicorn.run(app, host="0.0.0.0", port=8000) And when... GitHub · github.com [1] Setting an additional log handler to the uvicorn logger for access logs in fastapi [2] was not straightforward, but This post was very helpful. @app.on_event("startup") async def startup_event(): logger = logging.getLogger("uvicorn.access") handler = logging.StreamHandler() handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) logger.addHandler(handler) References: [1]: https://github.com/tiangolo/fastapi/issues/1508 [2]: /fastapi/
External Link stackoverflow.com [1] Setting tags in your fastapi endpoints will group them in the docs. You can also set some metadata around the tags to get nice descriptions. Here is a full example from the post. from fastapi import FastAPI tags_metadata = [ {"name": "Get Methods", "description": "One other way around"}, {"name": "Post Methods", "description": "Keep doing this"}, {"name": "Delete Methods", "description": "KILL 'EM ALL"}, {"name": "Put Methods", "description": "Boring"}, ] app = FastAPI(openapi_tags=tags_metadata) @app.delete("/items", tags=["Delete Methods"]) @app.put("/items", tags=["Put Methods"]) @app.post("/items", tags=["Post Methods"]) @app.get("/items", tags=["Get Methods"]) async def handle_items(): return References: [1]: https://stackoverflow.com/questions/63762387/how-to-group-fastapi-endpoints-in-swagger-ui#answer-63762765
waylon walker (@_WaylonWalker) on X Bloggers where do you put your markdown? X (formerly Twitter) · twitter.com [1] Most bloggers on my twitter blog right into a file that goes on git [2]. I kinda expected to have more database folk. I have my blog in markdown on git and the editing experience is top notch. I can just find files edit them in MY EDITOR, push them and I got a post. I am running thoughts in a sqlite database with a fastapi [3] backend, and holy crap the instant nature of posting feels so much better. Both sides have good points. References: [1]: https://twitter.com/_WaylonWalker/status/1734387536716308693 [2]: /glossary/git/ [3]: /fastapi/
Show some equivalent list comprehensions in filter examples · Issue #1068 · pallets/jinja I'm willing to write a pull-request for this, but I just want to see what people think before I write it. So the issue is this. I'm very familiar with python. I'm new to Jinja2. Often I find myself... GitHub · github.com [1] I often want to reach for non existing list comprehensions in jinja 2, Here are a few nice equivalents. a: {{ data | selectattr('x', 'gt', 5) | list }} b: {{ data | map(attribute='c') | list }} c: {{ data | selectattr('x', 'gt', 5) | map(attribute='c') | list }} References: [1]: https://github.com/pallets/jinja/issues/1068
External Link vi.stackexchange.com [1] I fixed my missing macro recording indicator that I lost and was never quite sure why. (because I forgot that I set cmdheight=0). vim.cmd [[ autocmd RecordingEnter * set cmdheight=1 ]] vim.cmd [[ autocmd RecordingLeave * set cmdheight=0 ]] References: [1]: https://vi.stackexchange.com/questions/39947/nvim-vim-o-cmdheight-0-looses-the-recording-a-macro-messages

I am working on fokais.com’s signup page, and I want to hide the form input during an htmx request. I was seeing some issues where I was able to prevent spamming the submit button, but was still able to get one extra hit on it.

It also felt like nothing was happening while sending the email to the user for verification. Now I get the form to disappear and a spinner to show during the request.

html">HTML #

Let’s start off with the form. It uses htmx to submit a post request to the post_request route. Note that there is a spinner in the post_request with the htmx-indicator class.

The intent is to hide the spinner until the request is running, and hide all of the form input during the request.

<form
  id="signup-form"
  hx-swap-oob="outerHTML"
  class="m-4 mx-auto mb-6 flex w-80 flex-col rounded-lg b p-4 shadow-xlc shadow-cyan-500/10"
  method="POST"
  action="{{ url_for('post_signup') }}"
  hx-post="{{ url_for('post_signup') }}"
>

<!--markata-attribution-->
  <input
    class="mx-8 mt-6 mb-4 border border-black bg-zinc-900 p-1 text-center focus:bg-zinc-800"

<!--markata-attribution-->
    type="text"

<!--markata-attribution-->
    value="{{ full_name }}"

<!--markata-attribution-->
    name="full_name"

<!--markata-attribution-->
    placeholder="Full Name"
  />

<!--markata-attribution-->
  {% if full_name_error %}

<!--markata-attribution-->
  <label class="-mt-6 mb-6 mx-8 text-red-500 p-1 text-center">

<!--markata-attribution-->
    {{ full_name_error }}

<!--markata-attribution-->
  </label>

<!--markata-attribution-->
  {% endif %}

<!--markata-attribution-->
  <input
    class="mx-8 mb-4 border border-black bg-zinc-900 p-1 text-center focus:bg-zinc-800"

<!--markata-attribution-->
    type="text"

<!--markata-attribution-->
    value="{{ username }}"

<!--markata-attribution-->
    name="username"

<!--markata-attribution-->
    placeholder="username"
  />

<!--markata-attribution-->
  {% if username_error %}

<!--markata-attribution-->
  <label class="-mt-6 mb-6 mx-8 text-red-500 p-1 text-center">

<!--markata-attribution-->
    {{ username_error }}

<!--markata-attribution-->
  </label>

<!--markata-attribution-->
  {% endif %}

<!--markata-attribution-->
  <input
    class="mx-8 mb-4 border border-black bg-zinc-900 p-1 text-center focus:bg-zinc-800"

<!--markata-attribution-->
    type="email"

<!--markata-attribution-->
    name="email"

<!--markata-attribution-->
    value="{{ email }}"

<!--markata-attribution-->
    placeholder="email"
  />

<!--markata-attribution-->
  {% if email_error %}

<!--markata-attribution-->
  <label class="-mt-6 mb-6 mx-8 text-red-500 p-1 text-center">

<!--markata-attribution-->
    {{ email_error }}

<!--markata-attribution-->
  </label>

<!--markata-attribution-->
  {% endif %}

<!--markata-attribution-->
  <input
    class="mx-auto w-32 mb-4 border border-black bg-purple-900 p-1 text-center focus:bg-zinc-800"

<!--markata-attribution-->
    type="submit"

<!--markata-attribution-->
    value="sign up"
  />

<!--markata-attribution-->
  <div role="status" class="mx-auto htmx-indicator">

<!--markata-attribution-->
    <svg

<!--markata-attribution-->
      class="mx-auto animate-spin h-5 w-5 text-white"

<!--markata-attribution-->
      xmlns="https://www.w3.org/2000/svg"

<!--markata-attribution-->
      fill="none"

<!--markata-attribution-->
      viewBox="0 0 24 24"
    >

<!--markata-attribution-->
      <circle

<!--markata-attribution-->
        class="opacity-25"

<!--markata-attribution-->
        cx="12"

<!--markata-attribution-->
        cy="12"

<!--markata-attribution-->
        r="10"

<!--markata-attribution-->
        stroke="currentColor"

<!--markata-attribution-->
        stroke-width="4"
      ></circle>

<!--markata-attribution-->
      <path

<!--markata-attribution-->
        class="opacity-75"

<!--markata-attribution-->
        fill="currentColor"
        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
      ></path>

<!--markata-attribution-->
    </svg>

<!--markata-attribution-->
    <p>Signing up...</p>

<!--markata-attribution-->
  </div>

<!--markata-attribution-->
</form>

Yes this is styled using tailwindcss.

https://waylonwalker.com/still-loving-tailwind/

CSS #

Let’s take a look at how we achieve switching between only spinner an only form inputs using css.

.htmx-indicator {
  @apply hidden;
  opacity: 0;
  transition: opacity 500ms ease-in;
}
.htmx-request button,
.htmx-request input[type="submit"],
.htmx-request input,
.htmx-request label {
  @apply hidden;
}
.htmx-request .htmx-indicator {
  opacity: 1;
  @apply block;
}
.htmx-request.htmx-indicator {
  opacity: 1;
  @apply block;
}

Final Result #

Here is the final result of me signing up for a new account in fokais.

GitHub - DataDog/ddqa: Datadog's QA manager for releases of GitHub repositories Datadog's QA manager for releases of GitHub repositories - DataDog/ddqa GitHub · github.com [1] DataDog ddqa is building out a textual app and deploying it with pyapp. They have CI setup to fully build and cross compile their textual tui into github releases that you can just download from their releases page. This is something I am looking at for markata. This would be pretty sweet to be able to make it just work on places like windows. It would also be interesting to try to build a full desktop app with pyapp. References: [1]: https://github.com/DataDog/ddqa
Check out ddqa [1] by DataDog [2]. It’s a well-crafted project with great potential. Datadog’s QA manager for releases of GitHub repositories References: [1]: https://github.com/DataDog/ddqa [2]: https://github.com/DataDog
I like cross-rs’s [1] project cross [2]. “Zero setup” cross compilation and “cross testing” of Rust crates References: [1]: https://github.com/cross-rs [2]: https://github.com/cross-rs/cross
If you’re into interesting projects, don’t miss out on pyapp [1], created by ofek [2]. Runtime installer for Python applications References: [1]: https://github.com/ofek/pyapp [2]: https://github.com/ofek
Adam Wathan (@adamwathan) on X Hear me out. X (formerly Twitter) · twitter.com [1] I’m going to give this trick a shot on my sites, and see how I like it. * { min-width: 0 } Down in the comments @adamwathan [2] goes on to say. Basically every layout overflow bug ever boils down to some flex or grid child needing min-width: 0 😄 Oh and @ryanflorence [3] also says in the comments. I … do this. References: [1]: https://twitter.com/adamwathan/status/1734696245015494711 [2]: https://twitter.com/adamwathan/ [3]: https://twitter.com/ryanflorence
External Link tushar.lol [1] Nice message by @tusharsadhwani [2]. Write it down. You had to dig deeper than face value at something. Write it down. You had to combine multiple pages of docs. Write it down. Someting was simply not obvious to you at first and it took someone else to give you that ah ha moment. Write it down. You had a small discovery that had a marginal impact on your day. Write it down. A blog does not have to be a Blog, it can be small meaningful posts. There are absolutely no rules. If you think you are going to end up with too many posts, that is a solvable problem, make a search, curate your favorite posts, make multiple feeds. At the end of the day. Write it down. This post itself is a thought, the smallest component to my blogging strategy. Write it down. References: [1]: https://tushar.lol/post/write-a-blog/ [2]: https://twitter.com/sadhlife