The trickiness of HTML checkbox

I'm using Lustre framework to rebuild the Admin area of this blog. When implementing the form for editing blog post, I'm surprised how tricky to handle the checkbox, which may look simple at first.

In CRUD applications, people often use the checkbox to represent a boolean field. The "checked" status is for True and unchecked is for False. Take this form as example, when I want to publish a post, I tick the "Published" checkbox and save. If I want to unpublish, I untick and save.

Checkbox as boolean field

Most of people don't see any issue with this usage. When I make frontend apps with VueJS, with an edit form like this, I often bind each <input> element with a reactive variable, via v-model:

...

Lustre / Gleam: How to create modal popup

Modal dialog is a often used UI element, but in web tech, developers used to spend quite much effort to implement it, before the introduction of CSS frameworks like Bootstrap. It was tricky to position the dialog in the center of the window, to blur the content behind it. It was tricky to let user close the popup by clicking outside it.

It is until the HTML standard introduces the native <dialog> element. Now developers can create a modal popup with ease, except if their users are using Safari, which often lags behind the modern web features. Put Safari aside, now we see how to create the native modal popup in Lustre framework (Gleam language).

My use case is the post compose form of this blog. The original content is in Markdown. The form has a "Preview" button so that if I click it, a modal popup appears and loads the rendered HTML of that Markdown code.

Form

...

Lustre / Gleam: How to open confirm dialog

Given that we have a list of items, and a "delete" button for each item. We want that when user clicks the button, a confirm dialog will appear, asking user one more time, before proceeding with API call to delete the item from the database.

Delete confirmation

Here is how to do that in Lustre (a frontend web framework in Gleam language). The dialog in this example is the HTML native dialog created by window.confirm() method, in case we want some thing quick and simple. If you want to use <dialog> element, I will write later.

First, let's write a view function to prepare the HTML:

...

structlog-journald, ghi log vào journald

Hôm nay mình phát hành thư viện structlog-journald v0.5.0. Thư viện này tận dụng lợi thế của journald để giúp debug hệ thống multi-tenant dễ dàng hơn. Đây là những hệ thống phục vụ nhiều khách hàng, với cách làm thông thường thì log của nhiều khách hàng sẽ trộn lẫn với nhau gây khó khăn cho việc debug. Thư viện này cho phép gắn thông tin phụ (như ID khách hàng) khi ghi log rồi sau đó khi xem log bằng journalctl có thể lọc theo thông tin phụ đó. Bằng cách đó ta có thể tập trung vào một đối tượng cụ thể để truy vết.

Minh họa:

demo

...

Make Nginx Unit controllable from non-root user

Recently I heard about Nginx Unit, a piece of software which lets you run Python web application on production with less components. It's like you let Nginx run your Python code, no longer Nginx - Gunicorn separation. So I installed it and learned how to use, but the default setup is not convenient: You have to switch to root user too often. So I share extra steps of setup to save you from it.

Nginx Unit is not configured via file like Nginx. It is done via HTTP API, which is nice because Nginx Unit can get update with new configuration without restarting, although I don't know what is the benefit over using SIGHUP signal to trigger rereading. The API communication is done via Unix domain socket, leveraging Linux authentication for restricting access, which is very reasonable because we don't have to remember port, username and password. But the issue is that, the default setup makes the socket writable by root only.

Unit control socket

The annoyance come from the combination of these factors:

...

Đồ chơi để thấy GraphQL đỡ phiền

GraphQL là một dạng thiết kế HTTP API được dùng rộng rãi. Mặt lợi của nó thì không cần bàn. Tuy nhiên mình và có thể các bạn cũng thấy hơi phiền vì nó dài dòng. Bài này sẽ giới thiệu một số phương tiện phần mềm để làm việc với nó thoải mái hơn, ở phía client.

Python: Cách dùng Pydantic để kiểm tra hợp lệ

Lấy ví dụ API của BirdWeather. Đây là kho dữ liệu của các trạm thu thập tiếng chim hót, phục vụ nghiên cứu nhận dạng chim từ tiếng hót. Ta sẽ gọi vào truy vấn stations để lấy danh sách các trạm. Một response mẫu sẽ trông như sau:

...

Triển khai tự động ứng dụng web Python

Gần đây nghe sự cố máy chủ DeepSeek bị lộ dữ liệu do để mở cổng database toang hoác, làm tôi nhớ đến cách triển khai ứng dụng web của mình, trong đó mình đóng cổng database luôn, chỉ cho truy cập qua Unix domain socket (dạng file), và cũng không cần tạo password, không cần nhớ, không cần giấu password. Thủ thuật này đã được nhắc đến trong một bài blog khác bằng tiếng Anh, nay dịch ra cho anh em tham khảo. Bài viết đó nói về một chủ đề rộng hơn là "cách triển khai ứng dụng web Python một cách tự động".

Gần đây tôi thấy một câu hỏi từ một đồng nghiệp Python, làm thế nào để triển khai ứng dụng Django mà không cần phải SSH thủ công vào máy chủ và chạy các lệnh. Phong cách này là "single server deployment". triển khai trên một máy chủ duy nhất, nơi bạn đặt tất cả các thành phần, từ mã ứng dụng, cơ sở dữ liệu, đến các tệp tĩnh, tệp media, trên cùng một máy chủ. Không có Docker tham gia. Với kiểu triển khai này, chúng ta sẽ cần một cách nào đó để cung cấp phiên bản mới của ứng dụng mỗi khi mã mới được đẩy lên nhánh "release" của kho lưu trữ Git.

Tại sao cần tự động hóa? Vì làm đi làm lại những việc này rất nhàm chán:

  • SSH vào máy chủ, cd vào thư mục cài đặt.
...

How to automatically deploy Python web application

Recently I saw a question from a Python fellow, how to deploy Django application without manually SSH to server and run commands. This style is single-server deployment, where you put all components, from the application code, database, to static, media files, in the same server. No Docker involves. With this deployment strategy, we will need some way to deliver new version of our app everytime new code is pushed to the "release" branch of Git repository. Here is a guide.

Why we need automation? Because it is boring to do these things by hand again and again:

  • SSH to the server, cd to the installation folder.
  • Run git pull.
  • Run commands to stop your services.
...

So sánh hệ thống kiểu của Python và TypeScript

Với hơn một nửa công việc hàng ngày là làm web, Python và JavaScript là hai ngôn ngữ mình dùng nhiều. Đây vốn là hai ngôn ngữ "kiểu động" (dynamic type), nhưng mình vẫn tận dụng hệ thống kiểu (type system) của chúng để viết như với một ngôn ngữ "kiểu tĩnh" (static type). Sau một thời gian thì mình rút ra được một số kinh nghiệm để làm việc với hai hệ này.

Thật ra, ngôn ngữ JavaScript không có ký hiệu kiểu, nên nói chính xác hơn là mình đang dùng TypeScript chứ không phải JavaScript. Trước hết, người đã làm quen với JavaScript mà được giới thiệu về TypeScript thì sẽ bật lên một câu hỏi, tại sao chúng là ngôn ngữ dynamic type thì lại mất công viết như static type làm gì. Đó là vì những ích lợi sau:

  • Giúp các công cụ kiểm tra (static analysis) như MyPy, tsc hiểu được code mình, để phát hiện được bug tiềm tàng trong những trường hợp ngách mà mình chưa test.
  • Giúp các trình soạn thảo (code editor, IDE) hiểu được biến đang có kiểu gì, để đưa ra gợi ý autocomplete đúng hơn.
...

Truy xuất mảng trong JavaScript một cách an toàn

Gần đây mới biết rằng trong JavaScript, khi truy xuất một phần tử trong mảng sau khi kiểm tra trước độ dài của mảng, thì vẫn không đảm bảo được rằng phần tử đó tồn tại.

Ví dụ trong đoạn code 1, biến "first" tại dòng 3 có thể bị undefined, dẫn đến "tz" tại dòng 4 cũng bị undefined theo. Lý do là mảng trong JS là mảng thưa, cho phép các vị trí phần tử không liên tục. Tức là có thể có phần tử ở vị trí 1 mà không có ở vị trí 0.

function useFirst(items: Date[]) {
  if (items.length) {
...