Introduction
Data scientists and AI engineers spend a surprising amount of time talking to HTTP endpoints.
A FastAPI service wraps a YOLO model. A LangGraph agent calls an OpenAI tool. A retrieval
service exposes a vector search route. Every one of those workflows depends on requests
behaving the way you expect — correct status codes, correct payload shape, correct headers.
curl works, but it stops scaling
the moment you’re juggling collections of endpoints, environment variables, file uploads,
and pre/post-response assertions.
Requestly is an API testing tool now owned by BrowserStack that ships as a desktop app and a Chrome extension. It’s free, open source, and tuned for the kind of workflows data and ML teams actually run — multipart file uploads to vision APIs, base64 image responses, model-size parameters, and quick environment-variable swaps. This article walks through using Requestly to test a real FastAPI YOLO v26 service that exposes object detection, classification, and segmentation endpoints.
Table of contents
- What Requestly is
- Why ML and AI engineers need a real API tester
- Installing Requestly
- The example project: a FastAPI YOLO v26 service
- Creating a collection
- Testing a GET endpoint
- Testing a POST endpoint with file upload
- Decoding base64 image responses
- Environment variables and placeholders
- Pre-request and post-response test scripts
- Collection runner for batch testing
- Integrating with LLM and ML APIs — OpenAI, Anthropic, Hugging Face
- Requestly vs Postman, Bruno, Hoppscotch, Apidog
- Best practices for API testing in ML projects
- Common mistakes to avoid
- Conclusion
- Frequently asked questions
What Requestly is
Requestly is an API client and HTTP debugging tool. The product covers three loosely connected jobs in one application: sending and inspecting API requests, intercepting and modifying network traffic in the browser, and writing assertions against responses. For data and ML workflows the first and third parts matter most — the request builder, the collection runner, and the scripting hooks.
Core capabilities
- HTTP request builder with GET / POST / PUT / DELETE and full header control
- Multipart form-data uploads for files and binary payloads
- Collections with descriptions and reusable variables
- Environment variables with placeholder substitution
- Pre-request scripts and post-response assertions
- Collection runner for batch execution
What sets it apart
- Free and open source after the BrowserStack acquisition
- Lightweight desktop app — not an Electron monster
- Inline HTML preview for endpoints that return rendered pages
- AI-assisted test-case generation for status and header checks
- Chrome extension for in-browser request interception
Why ML and AI engineers need a real API tester
Most ML tutorials stop at “train a model and call it from a notebook.” Production is where the API layer starts mattering. The moment you wrap a model in FastAPI, Flask, or a serverless function, you’re back in normal web-engineering land — status codes, content types, retries, payload sizes. A scripting REPL won’t catch the regressions that a proper API tester will.
Model endpoint debugging
Did inference fail because the model is bad, or because the request shape was wrong? A dedicated client makes the difference between a 422 validation error and a real modelling bug obvious in seconds.
Reproducible test fixtures
Collections capture the exact request — URL, headers, body, file — so a teammate can hit your endpoint with the same payload and reproduce the bug without copying a 40-line curl command from Slack.
Pre-release smoke tests
Before pushing a model bump, run the collection against staging. Status 200, content-type matches, response size in range — three asserts that catch most breakage without writing pytest fixtures.
Installing Requestly
Head to requestly.com and click
download. You get two options: a desktop app (Windows, macOS, Linux) or a Chrome extension.
Pick the desktop app for testing local APIs — the extension is more useful for browser
traffic interception.
Quick setup
- Download the installer for your OS.
- Run the installer — double-click on Windows or drag to Applications on macOS.
- Open the app and sign in (optional — needed for sync across machines).
- Create your first workspace.
The example project: a FastAPI YOLO v26 service
The walkthrough uses a small FastAPI service that wraps YOLO v26 for three computer vision tasks — object detection, classification, and segmentation. Each endpoint takes a multipart file upload and a string parameter for model size.
The service exposes:
GET /— HTML home pageGET /health— health checkPOST /api/v1/detect— object detectionPOST /api/v1/classify— image classificationPOST /api/v1/segment— instance segmentationGET /test— HTML test client
Spin up the project with uv:
# create and activate a virtual env
uv venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
# install dependencies
uv pip install -r requirements.txt
# run the FastAPI app on port 8080
uvicorn fastapi_app:app --reload --port 8080
Open http://127.0.0.1:8080/docs
to confirm Swagger lists every route. From here, Requestly takes over as the testing surface.
Creating a collection
A collection is a folder of related requests. For an ML service, group endpoints by domain —
one collection per model, or one per service. The walkthrough uses a single collection called
yolo-test-app.
Steps
- Click New → Collection.
- Name it
yolo-test-app. - Add a description — list every endpoint, its method, and what it returns.
- Save.
Tip: paste your OpenAPI spec or your FastAPI router code into an LLM and ask it to draft the collection description. It saves ten minutes of typing and gives teammates real context when they open the collection.
Testing a GET endpoint
Start with the simplest case — the home page. Inside the collection, create a new HTTP
request named home.
- Method:
GET - URL:
http://127.0.0.1:8080/ - Hit Send.
The response panel shows the raw HTML the FastAPI route returned. Requestly also renders the
HTML inline, so you can sanity-check what the browser would see without leaving the app.
Repeat the same flow for the test-client route at
/test.
Testing a POST endpoint with file upload
Now the interesting part. The classify, segment, and detect endpoints take a multipart payload
with two fields — file (the
image) and model_size (small,
medium, or large).
Configuring the classify request
- Create a new HTTP request named
classify. - Method:
POST. - URL:
http://127.0.0.1:8080/api/v1/classify. - Body tab → pick multipart/form-data.
- Add key
filewith type file, attach a dog-and-couch image. - Add key
model_sizewith type text, valuemedium. - Save and Send.
The first call is slow — the model is loading into memory. After that you should see a JSON response like:
{
"success": true,
"classify": {
"label": "Siberian husky",
"confidence": 0.91
},
"image_data": "iVBORw0KGgoAAAANSUhEUgAA..."
}
Repeat for /api/v1/segment and
/api/v1/detect. Same body shape,
different routes. Segmentation returns bounding-box coordinates; detection returns class labels
plus boxes.
Decoding base64 image responses
Many vision APIs return an annotated image as a base64 string inside the JSON response. That string is unreadable in the response viewer. Two quick options:
- Paste the string into any online base64-to-image decoder (search base64 decode image) to view the annotated result.
- Decode it locally with a one-liner:
import base64
with open("annotated.png", "wb") as f:
f.write(base64.b64decode(response_json["image_data"]))
For detection on a dog-and-couch image, you should see two boxes — one labelled
dog 0.83 and one labelled
couch.
Environment variables and placeholders
Hard-coding http://127.0.0.1:8080
across ten requests is the kind of mistake you only make once. Requestly supports
collection-scoped variables you can reference with a placeholder.
Setting up variables
- Open the collection → Variables tab.
- Add a variable: name
url, type string, initial valuehttp://127.0.0.1:8080. - Add another: name
home, valuehttp://127.0.0.1:8080/. - Save.
Now reference them inside any request URL with double-brace placeholders:
{{url}}/api/v1/classify
{{url}}/api/v1/segment
{{url}}/api/v1/detect
Switching from local to staging is one variable edit. For production you’d add a
prod_url variable and either
swap the placeholder or move to a separate environment.
Mark API keys and tokens as secret when you add them. Requestly will mask the value in the UI and avoid leaking it in shared exports.
Pre-request and post-response test scripts
Each request has a pre-request hook (runs before the call) and a post-response hook (runs after). Use post-response to assert on the response — status codes, headers, JSON shape.
A minimal status and content-type check for the home route:
// post-response script for GET /
rq.test("status is 200", function () {
rq.expect(rq.response.code).to.equal(200);
});
rq.test("content-type is text/html", function () {
rq.expect(rq.response.headers["content-type"]).to.include("text/html");
});
The app has an AI-generate option — click it and Requestly drafts assertions based on the request. For routine status and header checks it’s a fair starting point, though you’ll still hand-write the schema-sensitive ones.
A more interesting assertion for the classify endpoint:
// post-response script for POST /api/v1/classify
const body = rq.response.json();
rq.test("success flag is true", function () {
rq.expect(body.success).to.equal(true);
});
rq.test("classify object has a label", function () {
rq.expect(body.classify).to.have.property("label");
});
rq.test("confidence is between 0 and 1", function () {
rq.expect(body.classify.confidence).to.be.within(0, 1);
});
Pre-request hooks are useful for things like generating a timestamp or a request ID:
// pre-request script
const timestamp = Date.now();
const requestId = crypto.randomUUID();
rq.variables.set("timestamp", timestamp);
rq.variables.set("request_id", requestId);
console.log("timestamp:", timestamp);
console.log("request_id:", requestId);
Collection runner for batch testing
Running one request at a time is fine while you’re building. For regression checks you want every endpoint hit in order, with all assertions running, in one click.
Using the runner
- Open the collection and click Runner.
- Tick the requests you want to include — or run all of them.
- Hit Run.
- Watch the green and red dots next to each assertion.
Two green ticks per route means status and content-type passed. A red dot is a regression to
investigate. The runner becomes a smoke test you can fire before any model deployment —
same idea as pytest, but at the
HTTP boundary instead of inside the codebase.
Integrating with LLM and ML APIs
The same patterns apply to third-party model APIs. You define a collection per provider, store the API key as a secret variable, and reuse it across every request.
OpenAI Chat Completions
POST https://api.openai.com/v1/chat/completions
Headers:
Authorization: Bearer
Content-Type: application/json
Body (raw JSON):
{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "Hello"}
]
}
Anthropic Messages
POST https://api.anthropic.com/v1/messages
Headers:
x-api-key:
anthropic-version: 2023-06-01
Content-Type: application/json
Body (raw JSON):
{
"model": "claude-opus-4-5",
"max_tokens": 256,
"messages": [
{"role": "user", "content": "Hello"}
]
}
Hugging Face Inference
POST https://api-inference.huggingface.co/models/bert-base-uncased
Headers:
Authorization: Bearer
Content-Type: application/json
Body (raw JSON):
{
"inputs": "The capital of France is [MASK]."
}
Local Ollama server
POST http://localhost:11434/api/generate
Headers:
Content-Type: application/json
Body (raw JSON):
{
"model": "llama3",
"prompt": "Hello",
"stream": false
}
For streaming responses (server-sent events from OpenAI or Anthropic), the body comes back as chunked text rather than a single JSON object. Requestly will display the stream — useful for confirming that your endpoint actually streams when it claims to.
Requestly vs Postman, Bruno, Hoppscotch, Apidog
Every team already has an API client they like. The question isn’t whether Requestly is objectively better — it’s whether the tradeoffs line up with how you work.
vs Postman
Postman is the incumbent. It’s feature-rich, well-documented, and bloated. Recent pricing changes and a forced cloud-sync default pushed a lot of teams to look elsewhere. Requestly is lighter, free, and keeps your data local unless you opt in.
vs Bruno
Bruno is git-friendly — collections are plain files you commit to a repo. If your team treats API specs as code, Bruno wins. Requestly trades that for a polished UI and better in-app preview.
vs Hoppscotch
Hoppscotch is open source and web-based by default. Great for quick checks from a browser tab. Requestly’s desktop-first approach handles local-network testing and large file uploads more comfortably.
vs Apidog
Apidog leans into the full API lifecycle — design, mock, document, test. If you want a single tool to replace Postman + Swagger + Mockoon, Apidog is the pitch. Requestly stays focused on testing and debugging, which is the lighter footprint.
Best practices for API testing in ML projects
Do this
- Keep one collection per service — not per project
- Use environment variables for every URL and API key
- Pin sample images and payloads inside the repo so collections are reproducible
- Write post-response assertions for status, content-type, and JSON shape
- Run the collection runner as a manual smoke test before any deployment
- Export collections to JSON and commit them next to the FastAPI code
Avoid this
- Hard-coding hostnames inside every request
- Storing API keys in plain text variables instead of secrets
- Letting collections drift from the actual route paths in code
- Skipping the runner step and trusting that “one good call” means the build is fine
- Treating an API client as a replacement for proper integration tests in CI
Common mistakes to avoid
-
Confusing form-data with raw JSON. FastAPI’s
UploadFileneeds multipart form-data. Sending a JSON body with a base64 string is a different endpoint contract entirely. -
Mismatched field names. The body parameter is
file, notimage. FastAPI returns 422 with a clear “field required” message — read it instead of assuming the server is broken. - First-call latency mistaken for a hang. Loading a vision model takes seconds. Add a longer timeout for the first request after server boot.
- Forgetting the port. Half the time the request fails because uvicorn is on 8080 and the collection points to 8000.
- Leaking API keys in exports. Always mark keys as secret before sharing a collection with a teammate.
Conclusion
For data scientists and ML engineers, the API layer is where most production bugs actually live. A focused tester like Requestly turns ad-hoc curl commands into a real test surface — reusable collections, environment variables, multipart file uploads, response assertions, and a runner that catches regressions before users do.
Pick one service, build one collection, write three post-response assertions, and run the collection before your next model deploy. That’s an afternoon of work and a meaningful reduction in “works on my notebook” failures.
Related reading
-
Building AI Agents for Production — Day 1
Agent concepts, framework choices, and the uv + LangChain dev environment—the project Requestly pairs with for API testing.
-
Evaluating LLM Chatbots and RAG Pipelines
Move beyond manual API testing to systematic evaluation—LangSmith, LLM-as-a-judge, and the four core RAG metrics.
-
Build Your Own Private AI Assistant with OpenClaw and Ollama
Set up a local Ollama endpoint—the perfect target for practicing API testing with Requestly on real model inference.