Healthchecks.io pinging API has always been based on UUIDs. Each Check in the system has its own unique and immutable UUID. To send a success signal (“ping”), clients make a request to https://hc-ping.com/ with check’s UUID added at the end:
To signal a start, a failure, or a particular exit status, clients can add more bits after the UUID:
This is conceptually simple and has worked quite well. It requires no additional authentication. The UUID value is the authentication, and the UUID “address space” is so vast nobody is going to find valid ping URLs by random guessing any time soon.
Still, UUID-based ping URLs have downsides too.
UUIDs are not particularly human-friendly. Unless you are good at memorizing UUIDs, it is not easy to associate a ping URL with a check just by looking at it. But it is easy to make mistakes when copy/pasting UUIDs around.
Each UUID is a secret. Therefore, if you have many things to monitor, you must keep many secrets. Let’s consider a specific example: a web application that does various housekeeping tasks on a schedule. Each housekeeping task has a corresponding Check in Healthchecks.io and a ping URL. The web app stores its configuration, including ping URLs, in environment variables:
BAR_TASK_URL, and so on. This is all well and good. But, as the web app grows and adds new types of housekeeping tasks, the number of environment variables can get out of hand. In one specific project I’m working on, there are already 15 environment variables for storing ping URLs, and there will likely be more. Wouldn’t it be nice if there was a way to store just a single secret, and derive all ping URLs from it?
Introducing: Slug URLs
In slug URLs, we replace the UUID with two components, a ping key and a slug:
Here’s a concrete example:
Slug URLs support start and failure signals the same way as UUID URLs do:
All checks in a single project share the same ping key. You can look up or generate the ping key in your project’s Settings screen, right next to your project’s API keys:
Healthchecks.io derives slug from Check’s name using Django’s slugify function. The slugify function applies the following transformations:
- Converts to ASCII.
- Converts to lowercase.
- Removes characters that aren’t alphanumerics, underscores, hyphens, or whitespace.
- Replaces any whitespace or repeated hyphens with single hyphens.
- Removes leading and trailing whitespace, hyphens, and underscores.
Here are a few specific examples of check names and the resulting slugs:
|server1 -> server2
Going back to the web app with housekeeping tasks example, with slug URLs the web app would need to store just one secret – the pinging key, and would be able to construct all ping URLs off that. Here is a rough example in Python:
// ... do some work here ...
requests.get("https://hc-ping.com/%s/foo_task" % os.getenv("PING_KEY"))
The ping URLs are also more human-friendly. The slug part helps you tell them apart.
Q: How can I use slug URLs in my Healthchecks.io project?
A: First, generate the ping key in your project’s Settings page. Next, click on “slug” on the Checks page:
Q: What if a check has no name?
A: The check will have no corresponding slug URL then:
Q: What if multiple checks in the project have the same name?
A: They will also have the same slug. When you try to ping them, you will get an HTTP 409 response with the text “ambiguous slug” in the response body.
Q: Can I use UUID and slug URLs at the same time?
A: Yes, you can use UUID URLs and slug URLs interchangeably.
Q: Then what does the uuid / slug selector do, exactly?
A: It selects which URL format is used for display in the list and details views on Healthchecks.io.
Slug URLs are implemented and ready for use on Healthchecks.io. This is a brand new feature and it will likely receive refinements over time. If you notice problems when using slug URLs, or want to suggest improvements, please send your feedback to firstname.lastname@example.org. I will appreciate it!