Add /random endpoint to display a random http.cat image.#260
Add /random endpoint to display a random http.cat image.#260taichikuji wants to merge 2 commits intohttpcats:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new /random route to the Next.js app that selects a random HTTP status code from the existing statuses dictionary and redirects the user to the corresponding status page.
Changes:
- Introduces
app/random/page.tsxto choose a random status code from@/lib/statuses. - Redirects requests for
/randomto/status/{randomStatus}.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
app/random/page.tsx
Outdated
| import { redirect } from 'next/navigation'; | ||
|
|
||
| import statuses from '@/lib/statuses'; | ||
|
|
||
| export default function Random() { | ||
| const statusCodes = Object.keys(statuses); | ||
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | ||
|
|
||
| redirect(`/status/${randomStatus}`); |
There was a problem hiding this comment.
Because the project is configured with output: 'export' (static export), this page will be prerendered at build time. That means Math.random() will be evaluated during the build and /random will always redirect to the same status code in production. To make /random vary per request on a static export, implement the selection/redirect on the client (e.g., a client component that picks a random code in an effect and navigates with router.replace/window.location), or change the app away from static export if a true HTTP redirect per request is required.
| import { redirect } from 'next/navigation'; | |
| import statuses from '@/lib/statuses'; | |
| export default function Random() { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| redirect(`/status/${randomStatus}`); | |
| 'use client'; | |
| import { redirect } from 'next/navigation'; | |
| import { useEffect } from 'react'; | |
| import { useRouter } from 'next/navigation'; | |
| import statuses from '@/lib/statuses'; | |
| export default function Random() { | |
| const router = useRouter(); | |
| useEffect(() => { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| router.replace(`/status/${randomStatus}`); | |
| }, [router]); | |
| return null; |
|
Hi @taichikuji , thanks for the PR. The core routing of http.cat happens in the Nginx configuration (not provided in this repo). It has a rewrite rule that maps the URL path to an image file, so that So, to me, the right place to implement this Now, @copilot 's suggested fix to the PR may also work, it may impact the user experience a bit with the redirect and all, but it's simpler and keeps the logic in the codebase. |
|
Absolutely understandable, if it's implemented outside the repository, then I'll close the PR, unless your suggestion would be to implement the changes indicated by Copilot. I can implement it in another commit. I will send the commit soon with those suggestions in place, thanks again! |
|
How would you implement the logic in NginX? OTOH I would assume you'd need a scripting language (a subset of JS + Lua is available through extensions -- they have an impact on Certbot however). |
|
If there's anything else that should be done or is required to get the PR approved, let me know! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| useEffect(() => { | ||
| const statusCodes = Object.keys(statuses); | ||
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | ||
|
|
||
| router.replace(`/status/${randomStatus}`); | ||
| }, [router]); | ||
|
|
||
| return null; |
There was a problem hiding this comment.
return null makes /random render a blank page while waiting for the effect to run (and it will stay blank if JS is disabled or if navigation fails). Consider rendering a small fallback like “Redirecting…” and/or a link/button to retry so the route remains usable and accessible even when the client-side redirect doesn’t happen immediately.
| useEffect(() => { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| router.replace(`/status/${randomStatus}`); | |
| }, [router]); | |
| return null; | |
| const redirectToRandomStatus = () => { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| router.replace(`/status/${randomStatus}`); | |
| }; | |
| useEffect(() => { | |
| redirectToRandomStatus(); | |
| }, [router]); | |
| return ( | |
| <main> | |
| <p>Redirecting to a random status page…</p> | |
| <button type="button" onClick={redirectToRandomStatus}> | |
| Try again | |
| </button> | |
| </main> | |
| ); |
| import { useRouter } from 'next/navigation'; | ||
|
|
||
| import statuses from '@/lib/statuses'; | ||
|
|
||
| export default function Random() { | ||
| const router = useRouter(); | ||
|
|
||
| useEffect(() => { | ||
| const statusCodes = Object.keys(statuses); | ||
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | ||
|
|
||
| router.replace(`/status/${randomStatus}`); | ||
| }, [router]); |
There was a problem hiding this comment.
/random currently redirects to /status/{code} via router.replace. The requested behavior in issue #255 (and the existing “Usage” section on the homepage) treats https://http.cat/{code} (optionally with .jpg) as the canonical endpoint, i.e., /random -> /403 -> /404 -> /200 ....
If /random is meant to match that behavior, redirect to /${randomStatus} (or /${randomStatus}.jpg) instead. Since there’s no Next route for /{code}, a Next.js client-side navigation would likely hit the app 404; use a full navigation (e.g., window.location.replace(...)) to reach the non-Next/nginx-served image endpoint.
| import { useRouter } from 'next/navigation'; | |
| import statuses from '@/lib/statuses'; | |
| export default function Random() { | |
| const router = useRouter(); | |
| useEffect(() => { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| router.replace(`/status/${randomStatus}`); | |
| }, [router]); | |
| import statuses from '@/lib/statuses'; | |
| export default function Random() { | |
| useEffect(() => { | |
| const statusCodes = Object.keys(statuses); | |
| const randomStatus = statusCodes[Math.floor(Math.random() * statusCodes.length)]; | |
| window.location.replace(`/${randomStatus}`); | |
| }, []); |
|
@Ryuno-Ki yes using either JS or Lua. Maybe I'm missing something, but I can't see how that would impact certbot. |
Previous version (Debian Bookworm and older) couldn't handle |
Fixes #255
This is a basic implementation on the issue request #255, please let me know if this is implemented correctly according to the project's coding style and instructions.
If there's any request to modify it, maybe to the Components section, I can do that as well.
The way it works is the following:
Upon visiting http.cat/random, it triggers this code (aka
app/random/page.tsx). It will pull the http dictionary data fromstatuses.jsand do a Math.random() on it. This will pull a pseudo-random value which it will then redirect towards.What do you think? Thanks :)