This content originally appeared on HackerNoon and was authored by Maximiliano Contieri
Misusing query parameters complicates API maintenance
TL;DR: Use URL paths or headers for API versioning.
Problems 😔
- Confusing parameters
- High maintenance
- Inconsistent versioning
- Client errors
- Misused queries
- Backward incompatibility
- URL clutter
- Hidden complexity
- Wrong semantics
- Parameter collisions
- Breaking changes
Solutions 😃
- Adopt URL paths
- Avoid query parameters
- Prefer headers
- Version on breaking changes
- Keep old versions running
- Deprecate old versions carefully
Context 💬
When you change an API in a way that breaks existing clients, you create problems.
\ To avoid this, you must version your API.
\ Versioning lets you add new features or change behavior without stopping old clients from working.
\ You usually put the version number in the API URL path, HTTP headers, or, less commonly, in query parameters.
\ Each method has pros and cons. URL path versioning is simple and visible. Header versioning keeps URLs clean but adds complexity.
\ Query parameters can clutter URLs and can be confusing. Use versioning only for breaking changes. Managing multiple versions increases maintenance work but ensures reliability and user trust.
Sample Code 📖
Wrong ❌
<?php
// Misusing query parameters for versioning
// https://eratostenes.com/api/primes?limit=10&version=2
// Version 2 is faster!
$version = $_GET['version'] ?? '1';
if ($version === '1') {
echo json_encode(['data' => 'Response from API v1']);
} elseif ($version === '2') {
echo json_encode(['data' => 'Response from API v2']);
} else {
http_response_code(400);
echo json_encode(['error' => 'Unsupported API version']);
}
// This handling with IF/Switches is another code smell
Right 👉
<?php
// https://eratostenes.com/api/v2/primes?limit=10
// NOTICE /V2/
// Version 2 is faster!
$requestUri = $_SERVER['REQUEST_URI'];
if (preg_match('#^/v([0-9]+)/#', $requestUri, $matches)) {
$version = $matches[1];
} else {
$version = '1';
}
switch ($version) {
case '1':
echo json_encode(['data' => 'Response from API v1']);
break;
case '2':
echo json_encode(['data' => 'Response from API v2']);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unsupported API version']);
}
<?php
// Header-based API versioning example
// GET /api/primes?limit=12 HTTP/1.1
// Host: eratostenes.com
// Accept: application/vnd.myapi.v2+json
// NOTICE THE HEADER V2
$acceptHeader = $_SERVER['HTTP_ACCEPT'] ?? '';
if (preg_match('#application/vnd\.myapi\.v(\d+)\+json#',
$acceptHeader, $matches)) {
$version = $matches[1];
} else {
$version = '1';
}
switch ($version) {
case '1':
echo json_encode(['data' => 'Response from API v1']);
break;
case '2':
echo json_encode(['data' => 'Response from API v2']);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unsupported API version']);
}
Detection 🔍
- [x] Automatic
You can detect the smell when your endpoints include ?version=1.
\ Linters and API design reviews can flag query parameters used for versioning.
\ You can detect this smell if you see clients breaking after API changes or if versioning is done inconsistently.
\ Look for usage of query parameters to define versions or multiple undocumented methods.
\ Check if old versions still respond but are not explicitly maintained or documented.
Tags 🏷️
- APIs
Level 🔋
- [x] Intermediate
Why the Bijection Is Important 🗺️
API versions should map one-to-one with breaking changes in your domain model.
\ When you create versions for non-breaking changes, you break this MAPPER and create confusion about what constitutes a significant change.
\ This leads to version sprawl, where clients can't determine which version they actually need, making your API harder to consume and maintain.
\ When API versions correspond clearly to usage contracts, clients know what data and behavior to expect.
\ Breaking this one-to-one mapping by changing API behavior without versioning causes client confusion and runtime errors.
\ Clear versioning keeps this mapping intact and reliable.
AI Generation 🤖
AI generators may create code with inconsistent or no API versioning, especially if asked for simple examples.
\ AI generators often produce quick-and-dirty endpoints with query parameters. They optimize for speed, not semantics.
AI Detection 🧲
AI tools can detect this smell by analyzing endpoint patterns, comparing response schemas across versions, and identifying minimal differences between API versions.
\ They can suggest consolidating non-breaking changes into existing versions.
Try Them! 🛠
Remember: AI Assistants make lots of mistakes
Suggested Prompt: use API versions in the url
| Without Proper Instructions | With Specific Instructions | |----|----| | ChatGPT | ChatGPT | | Claude | Claude | | Perplexity | Perplexity | | Copilot | Copilot | | You | You | | Gemini | Gemini | | DeepSeek | DeepSeek | | Meta AI | Meta AI | | Grok | Grok | | Qwen | Qwen |
Conclusion 🏁
You need to build APIs for MCPs and AIs today.
\ API versioning protects your clients from breaking changes, but overuse creates maintenance nightmares and client confusion.
\ Version your APIs judiciously - only when you make breaking changes that would cause existing integrations to fail.
\ You need API versioning to keep your API reliable and backward-compatible when adding breaking changes.
\ Using the URL path for versions is simple and clear.
\ HTTP header versioning keeps URLs clean but adds complexity, while query parameter versioning should generally be avoided.
\ Maintain clear version documentation, test versions thoroughly, and deprecate old versions gradually.
\ This practice keeps your API users happy and your codebase maintainable.
Relations 👩❤️💋👨
https://hackernoon.com/code-smell-303-how-to-prevent-breaking-existing-clients-when-you-make-changes
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xii
https://hackernoon.com/code-smell-272-api-chain?embedable=true
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxxviii
Disclaimer 📘
Code Smells are my opinion.
Credits 🙏
Photo by Marcus Urbenz on Unsplash
If you program, you are an API designer. Good code is modular—each module has an API.
Joshua Bloch
https://hackernoon.com/400-thought-provoking-software-engineering-quotes?embedable=true
This article is part of the CodeSmell Series.
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd?embedable=true
\
This content originally appeared on HackerNoon and was authored by Maximiliano Contieri
Maximiliano Contieri | Sciencx (2025-09-14T13:00:07+00:00) Code Smell 309 – Query Parameter API Versioning. Retrieved from https://www.scien.cx/2025/09/14/code-smell-309-query-parameter-api-versioning/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.