DEV Community

Mobeen Ahmed
Mobeen Ahmed

Posted on

End-to-end download testing with curl: my checklist before calling a feature live

I run a small video downloader on plain shared hosting, and I learned the hard way that a feature is not live just because the code looks right. The page can load, the button can work, and the download can still be broken. So before I call any change live on ramrom.io, I run the same end-to-end check with curl, from the terminal, like a visitor would.

1. Check the page itself first

I start with the tool page, not the API:

curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" https://ramrom.io/tiktok-downloader.html
Enter fullscreen mode Exit fullscreen mode

I want a 200 and a fast answer. This step also catches the silly mistakes: a missing file after an upload, a wrong filename, a page that only works from my own browser cache.

2. Test resolve.php with a real link

The heart of the downloader is resolve.php. It takes a pasted link, calls the provider, and returns the download options. I test it with a real link from one of my own accounts, never a sample URL from a provider's docs:

curl -s -X POST https://ramrom.io/api/resolve.php \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.tiktok.com/@me/video/1234567890"}'
Enter fullscreen mode Exit fullscreen mode

Does it have a video URL? A quality list? An error field hiding in there? A 200 status with an error body is still a failure, and curl will happily show me a 200 while the feature is dead. That is the most common trap in testing an API by hand.

3. Follow the file, not just the JSON

A resolve response is a promise, not a download. Next I take the file URL from that response and fetch its headers:

curl -s -I "https://provider-cdn.example/video.mp4"
Enter fullscreen mode Exit fullscreen mode

I check three things: the status is 200, the Content-Type is video/mp4, and there is a real Content-Length. If the content type is text/html, the "video" is an error page wearing a .mp4 name.

Then I download the first few kilobytes and look at them:

curl -s -r 0-1023 -o /tmp/test.mp4 "https://provider-cdn.example/video.mp4"
file /tmp/test.mp4
Enter fullscreen mode Exit fullscreen mode

file should say something like ISO Media file. If it says HTML document, the download is broken no matter what the JSON claimed.

4. Test the proxy path too

Some downloads go through my own proxy, so the file passes through my server. That path gets its own test, because it has its own failure modes: memory limits, timeouts, wrong headers. I run the proxy URL with curl and check the same three things again. If the direct link works but the proxy returns an empty file, the bug is in my code, not the provider, and only this test finds it.

5. Test the failures, not just the happy path

A checklist that only tests working links is half a checklist. I also send a deleted video link, a link from an unsupported site, and a link with tracking parameters and stray spaces. Each should get a plain, honest message, never a spinner that never stops. I also send the same link twice in a row, to make sure the rate limiter does not block a normal user. Each of these takes ten seconds, and each one has saved me from shipping a confusing error to real visitors.

6. Test on a slow connection

My visitors are often on mobile data, so I add --max-time 30 to the curl calls. If a provider call cannot answer in thirty seconds, it is not going to answer in a browser either. The timeout in my code should fire first, with an honest message, instead of the page hanging.

The rule I keep

Nothing is live until the whole chain works from the terminal: the page loads, resolve returns real options, the file URL serves a real MP4, the proxy path works, and the failures fail politely. It takes about five minutes, and it has stopped me from announcing a broken feature more times than I care to admit.

If you run a small tool site, build your own version of this list and run it the same way every time. The boring checklist is what makes the exciting launch actually work.

Top comments (0)