@samy_0202i
iAccount based inIndia
About this account
- Account based in
- India
- Connected via
- India Android App
Account-level information from X, not a live location or the device used for a specific post.
SDE2 at Paypal || IITian with a knack for coding and designing
India
Joined April 2020
- Tweets3.8K
- Following283
- Followers248
- Likes6.2K
Pinned Tweet
Just launched Anime Tracker on @ProductHunt 🎉
A free anime tracker with smart recs, a buddy system, sequel alerts, and a Chrome extension.
No ads. No feature locks. Ever.
Check it out → producthunt.com/products/ani…
🧵 Quick tour of what makes it different ↓
Sunday question to close the week: what's one API you love building against, and what makes it good?
Trying to collect examples that get the fundamentals right, not just the popular ones.
The older I get as an engineer, the more I care about the boring parts. Contracts, names, migration paths.
The clever parts are fun. The boring parts are what people actually depend on.
You can learn more about system design from one good public API's changelog than from most system design courses.
Watching how a real API evolves without breaking people is the actual lesson.
An underrated skill: reading someone else's API docs and being able to tell, in five minutes, whether the team behind it has been burned before.
Good pagination and honest error codes are scar tissue you can see.
Question: what's the one API design rule you now follow religiously because ignoring it burned you once?
Mine's on the list this week. Curious what's on yours.
This is post #9 of the You Can't Take It Back series.
Turning off an old endpoint with no warning is how you turn a customer into an ex-customer.
The quiet removal, or the deprecation buried in a changelog nobody reads, breaks integrations on your timeline instead of theirs. The code stops working, they find out from their own users, and the thing they lose faith in is you.
Fix: deprecate out loud and on a clock. Send Deprecation and Sunset headers on the old endpoint, publish a firm removal date, document the exact path to the replacement, and message the consumers you actually know about.
The rule underneath all of it: never remove before the sunset date, and give real lead time, not a week.
Follow along for more.
Engineering judgment: not every API needs all of this on day one.
An internal API with two callers you control can move fast and refactor freely. The full weight of versioning, deprecation windows, and idempotency keys is for contracts you can't unilaterally change.
The judgment is knowing which one you're building, and noticing the day an internal API quietly became a public one.
This is post #8 of the You Can't Take It Back series.
Two headers decide whether a rate-limited client backs off or hammers you: the remaining-quota header and Retry-After.
The naive version returns a bare 429, or worse a 500, with no guidance. The client has no idea when it's allowed back, so it retries right away and keeps retrying. Your limit is now generating the exact load it was meant to stop.
Fix: tell the client where it stands. Send X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on responses, and a Retry-After on every 429. A well-behaved client reads those and waits the right amount.
No headers today? Add them, document them, and put an alert on your 429 rate so a client gone rogue shows up before it's an incident.
Follow along for more.
We deprecated an old endpoint and gave it 30 days. Felt generous.
One partner had built their whole weekly export on it and only ran that job monthly. They hit the removed endpoint on day 34. Their report just silently returned nothing.
30 days isn't lead time if you don't know your callers' cadence.
This is post #7 of the You Can't Take It Back series.
POST /getUser isn't an endpoint. It's a note saying you stopped using HTTP.
When everything is a POST, you throw away meaning the whole stack relies on. GET is safe and cacheable. PUT and DELETE are idempotent, so a retry is safe. Proxies, caches, and client libraries all make decisions based on the method. POST-for-everything tells them nothing, so nothing gets cached and no retry is safe.
Fix: use the verb that matches the action. GET for reads with no side effects, POST to create, PUT or PATCH to update, DELETE to remove.
Already have POST /getThing routes? Add the correct verb equivalents, migrate clients, and deprecate the POST versions on a clock.
Follow along for more.
API tip: when validation fails, return which fields failed, not just that something failed.
{ "code": "validation_error", "fields": [{ "name": "email", "issue": "invalid_format" }] }
One vague 400 makes the client guess. A field-level list lets them point their user straight at the problem.
This is post #6 of the You Can't Take It Back series.
Why does renaming a database table break your public API?
Because the endpoint is named after the table. When your routes are /user_accounts and /user_orders_v2, you've welded the public contract to your storage layout. Split that table or move to a different store, and the change leaks straight through to every client.
Fix: name resources after the domain, not the database. Plain nouns. Shallow nesting, two or three levels at most. Names that stay stable even when the schema underneath is torn up and rebuilt.
Already exposing table-shaped routes? Add clean domain names as an alias layer over the same data, move clients across, and deprecate the old paths on a date.
Follow along for more.
Most breaking changes aren't a technical failure. They're a communication failure.
The rename, the removed field, the changed status code, they're all easy to survive if the people depending on you hear about it early and get a path off. The break hurts because nobody told them, not because the diff was large.
This is post #5 of the You Can't Take It Back series.
Stripe has evolved the same API for over a decade and never released a /v2. One rule makes that possible.
Additive-only change. New fields are optional. Existing fields never get renamed, removed, retyped, or hit with stricter validation than they had before.
Break any of that and clients fail silently, because they hard-coded the field name and type and have no idea you changed the contract under them.
Need to remove a field? Add its replacement, mark the old one deprecated with a date, keep both alive through the window, then drop the old one. The order matters.
Follow along for more.
I got it too just in case I win a PS lol.
#OnceHumanReceipt #OnceHumanConsole
Once Human is now on Console. Welcome to the strange worlds!
🎁Giveaway (Unlocked at 2,000 interactions): 2 winners, 1 console each. PS5 or Xbox Series S!
Free to play on PS5 and Xbox Series X|S, with full cross-play across PC, Mobile, and Console.
Strange worlds are yours to explore. Build your life, find your way to survive, and make it your own.
Event Period: Aug 25 - Sep 2
How to enter the giveaway:
Repost this post with the hashtag OnceHumanConsole and follow the official Once Human X account.
Notes:
1. The giveaway will be unlocked once this post reaches 2,000 total interactions (Reposts, Likes & Comments).
2. Two winners will be randomly selected on Sep 2 (PT) and announced on X.
3. Winners will be contacted via X DM. If we don’t receive a response within 7 days, the prize will be forfeited.
Sunday question: what's a piece of "boring" backend work that you secretly enjoy?
Mine is naming things well. Endpoints, fields, errors. A clean name saves a hundred future questions.
Weekend coding hits different. No standups, no Slack, no one waiting on the endpoint. Just you and the problem.
This is when I actually design the thing properly instead of just making it pass.
The best compliment an API can get is silence. No support tickets, no confused DMs, no "wait how does this work". Nobody notices the ones that just work.