{"id":1172,"date":"2026-04-05T10:00:00","date_gmt":"2026-04-05T09:00:00","guid":{"rendered":"https:\/\/wade.one\/blog\/?p=1172"},"modified":"2026-04-05T10:00:00","modified_gmt":"2026-04-05T09:00:00","slug":"what-makes-an-api-feel-nice-to-work-with","status":"publish","type":"post","link":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","title":{"rendered":"What Makes an API Feel Nice to Work With"},"content":{"rendered":"<p>I think the best APIs are the ones that get out of your way.<\/p>\n<p>That sounds obvious, but a lot of APIs still make you work harder than you should. They are technically usable, but only after you learn a bunch of exceptions, edge cases, and hidden rules that were never written down clearly. You can usually tell when an API was designed by someone who thought about the happy path and stopped there.<\/p>\n<p>What makes an API feel nice to work with is not cleverness. It is consistency.<\/p>\n<h2>Consistency matters more than fancy design<\/h2>\n<p>If an API is consistent, I can usually predict what a new endpoint will look like before I open the docs. That saves time. It also lowers the chance that I will make a dumb mistake while wiring it into a client, a script, or another service.<\/p>\n<p>Consistency shows up in small places:<\/p>\n<ul>\n<li>request shapes that follow the same pattern<\/li>\n<li>response envelopes that do not randomly change<\/li>\n<li>field names that mean one thing and stay that way<\/li>\n<li>pagination that works the same way everywhere<\/li>\n<li>filter and sort parameters that do not invent new rules for every route<\/li>\n<\/ul>\n<p>The problem with inconsistency is not just that it is annoying. It is that it forces me to keep re-reading the docs for things I should not have to re-learn.<\/p>\n<h2>Errors should be boring<\/h2>\n<p>Good APIs fail in a boring way.<\/p>\n<p>That means clear status codes, readable messages, and enough detail to fix the problem without guessing. I do not need a novel. I do need to know whether the issue is authentication, validation, permissions, rate limiting, or something broken on the server side.<\/p>\n<p>The worst error responses are the ones that are technically true but practically useless. <code>400 Bad Request<\/code> with no explanation is not helpful. Neither is a generic <code>Something went wrong<\/code> response that leaves you digging through logs just to understand whether the client is wrong or the service is dying.<\/p>\n<p>At minimum, I want:<\/p>\n<ul>\n<li>a stable error format<\/li>\n<li>a machine-readable error code<\/li>\n<li>a human-readable message<\/li>\n<li>field-level validation details when input is wrong<\/li>\n<\/ul>\n<p>If I can handle the error cleanly on the client side, that is usually because someone respected the fact that clients will fail in predictable ways.<\/p>\n<h2>Naming is part of the API<\/h2>\n<p>Bad naming makes an API feel sloppy even when the implementation is fine.<\/p>\n<p>I am not looking for poetic names. I am looking for names that mean what they say. If a field is called <code>status<\/code>, it should not sometimes mean lifecycle state and sometimes mean operational health. If a route is called <code>users<\/code>, I do not want to discover later that it really means <code>accounts<\/code>, <code>members<\/code>, and some half-baked profile object depending on context.<\/p>\n<p>The same applies to verbs. If an action is really a state transition, call it that. If it is a read, keep it a read. If a response contains a nested object, name it in a way that matches the real domain, not the internal table layout.<\/p>\n<p>Good naming makes the API easier to remember. Bad naming makes every integration feel slightly suspicious.<\/p>\n<h2>Auth should be obvious<\/h2>\n<p>Authentication and authorization are where a lot of APIs quietly become painful.<\/p>\n<p>If the auth model is unclear, every request becomes a small investigation. Am I missing a token, using the wrong scope, sending the wrong header, or hitting a permission boundary I did not know existed? That kind of friction adds up fast.<\/p>\n<p>A nice API makes auth boring too:<\/p>\n<ul>\n<li>the required auth method is obvious<\/li>\n<li>the permission model is documented in plain language<\/li>\n<li>unauthorized and forbidden failures are distinguishable<\/li>\n<li>test or sandbox auth behaves like production auth<\/li>\n<\/ul>\n<p>I especially dislike APIs that make auth feel like a secret handshake. If I have to read forum posts or reverse-engineer examples to figure out how to authenticate properly, the API is already losing me.<\/p>\n<h2>Docs do not need to be huge<\/h2>\n<p>Good docs are not exhaustive. They are useful.<\/p>\n<p>The best API docs usually answer the questions you actually have when integrating:<\/p>\n<ul>\n<li>what do I send<\/li>\n<li>what do I get back<\/li>\n<li>what can go wrong<\/li>\n<li>how do I paginate<\/li>\n<li>how do I authenticate<\/li>\n<li>what is optional and what is required<\/li>\n<\/ul>\n<p>Examples matter more than people admit. A small set of accurate examples beats a giant wall of reference material that nobody trusts.<\/p>\n<p>The other thing I care about is whether the docs match the implementation. Outdated docs are worse than missing docs because they make you doubt everything else on the page.<\/p>\n<h2>Predictability is the real feature<\/h2>\n<p>If I had to reduce all of this to one thing, it would be predictability.<\/p>\n<p>A nice API feels like it has rules that stay put. It does not surprise me with different shapes, hidden behavior, or one-off special cases unless there is a very good reason. That makes it easier to build on, easier to debug, and easier to trust.<\/p>\n<p>That is what I actually want from an API. Not brilliance. Not novelty. Just something that behaves the same way tomorrow that it behaved today.<\/p>\n<p>That is what saves time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A good API is not just functional. It is predictable, consistent, and easy to use without a lot of guesswork.<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[13,25],"tags":[66,68,67,69,70],"class_list":["post-1172","post","type-post","status-publish","format-standard","hentry","category-programming","category-software-engineer","tag-api","tag-auth","tag-developer-experience","tag-documentation","tag-errors"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>What Makes an API Feel Nice to Work With - wade.one<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"What Makes an API Feel Nice to Work With - wade.one\" \/>\n<meta property=\"og:description\" content=\"A good API is not just functional. It is predictable, consistent, and easy to use without a lot of guesswork.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/\" \/>\n<meta property=\"og:site_name\" content=\"wade.one\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-05T09:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/Wade-Logo-cropped.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1518\" \/>\n\t<meta property=\"og:image:height\" content=\"1506\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@wadewomersley\" \/>\n<meta name=\"twitter:site\" content=\"@wadewomersley\" \/>\n<meta name=\"twitter:label1\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"What Makes an API Feel Nice to Work With\",\"datePublished\":\"2026-04-05T09:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/\"},\"wordCount\":849,\"publisher\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\"},\"keywords\":[\"api\",\"auth\",\"developer-experience\",\"documentation\",\"errors\"],\"articleSection\":[\"Programming\",\"Software Engineer\"],\"inLanguage\":\"en-GB\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/\",\"name\":\"What Makes an API Feel Nice to Work With - wade.one\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#website\"},\"datePublished\":\"2026-04-05T09:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/2026\\\/04\\\/05\\\/what-makes-an-api-feel-nice-to-work-with\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wade.one\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"What Makes an API Feel Nice to Work With\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/\",\"name\":\"wade.one\",\"description\":\"wade womersley - york based software engineer\",\"publisher\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wade.one\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/#\\\/schema\\\/person\\\/8b4739f8f8bb2cff5d792d4b8779fcc3\",\"name\":\"Wade Womersley\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"url\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"contentUrl\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\",\"width\":202,\"height\":200,\"caption\":\"Wade Womersley\"},\"logo\":{\"@id\":\"https:\\\/\\\/wade.one\\\/blog\\\/wp-content\\\/uploads\\\/2015\\\/02\\\/200px.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"What Makes an API Feel Nice to Work With - wade.one","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","og_locale":"en_GB","og_type":"article","og_title":"What Makes an API Feel Nice to Work With - wade.one","og_description":"A good API is not just functional. It is predictable, consistent, and easy to use without a lot of guesswork.","og_url":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","og_site_name":"wade.one","article_published_time":"2026-04-05T09:00:00+00:00","og_image":[{"width":1518,"height":1506,"url":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/Wade-Logo-cropped.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_creator":"@wadewomersley","twitter_site":"@wadewomersley","twitter_misc":{"Estimated reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/#article","isPartOf":{"@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/"},"author":{"name":"","@id":""},"headline":"What Makes an API Feel Nice to Work With","datePublished":"2026-04-05T09:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/"},"wordCount":849,"publisher":{"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3"},"keywords":["api","auth","developer-experience","documentation","errors"],"articleSection":["Programming","Software Engineer"],"inLanguage":"en-GB"},{"@type":"WebPage","@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","url":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/","name":"What Makes an API Feel Nice to Work With - wade.one","isPartOf":{"@id":"https:\/\/wade.one\/blog\/#website"},"datePublished":"2026-04-05T09:00:00+00:00","breadcrumb":{"@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/wade.one\/blog\/2026\/04\/05\/what-makes-an-api-feel-nice-to-work-with\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wade.one\/blog\/"},{"@type":"ListItem","position":2,"name":"What Makes an API Feel Nice to Work With"}]},{"@type":"WebSite","@id":"https:\/\/wade.one\/blog\/#website","url":"https:\/\/wade.one\/blog\/","name":"wade.one","description":"wade womersley - york based software engineer","publisher":{"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wade.one\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":["Person","Organization"],"@id":"https:\/\/wade.one\/blog\/#\/schema\/person\/8b4739f8f8bb2cff5d792d4b8779fcc3","name":"Wade Womersley","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","url":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","contentUrl":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png","width":202,"height":200,"caption":"Wade Womersley"},"logo":{"@id":"https:\/\/wade.one\/blog\/wp-content\/uploads\/2015\/02\/200px.png"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":556,"url":"https:\/\/wade.one\/blog\/2011\/04\/25\/automating-implemented-methods-for-a-web-based-api\/","url_meta":{"origin":1172,"position":0},"title":"Automating &#8220;Implemented methods&#8221; for a web based API","author":"Wade","date":"April 25, 2011","format":false,"excerpt":"In my leedsphp talk last week I mentioned making a developer (and consumers) life easier by automatically implementing the allow methods functionality that your API may expose (e.g. you call PUT on a URL that only allows GET or POST). I did have an example slide there showing how to\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":521,"url":"https:\/\/wade.one\/blog\/2011\/03\/04\/using-ssl-in-restclient\/","url_meta":{"origin":1172,"position":1},"title":"Using SSL in RestClient","author":"Wade","date":"March 4, 2011","format":false,"excerpt":"UPDATE 14\/07\/2012: The author of the client has released version 2.5 a short while ago and also a video for using self-signed certificates in the client. RESTClient is a great little CLI and GUI tool for testing your REST API. I recently pushed a new API up in the office\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":553,"url":"https:\/\/wade.one\/blog\/2011\/04\/22\/leedsphp-talk-slides-uploaded\/","url_meta":{"origin":1172,"position":2},"title":"#leedsphp talk slides uploaded","author":"Wade","date":"April 22, 2011","format":false,"excerpt":"Finally got around to uploading my slides (sorry for the delay!) for my talk at leedsphp on Monday 18th. They are now available online at http:\/\/www.slideshare.net\/wadewomersley\/building-a-horizontally-scalable-api-in-php","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1168,"url":"https:\/\/wade.one\/blog\/2026\/04\/01\/why-i-still-like-serverless-for-small-teams\/","url_meta":{"origin":1172,"position":3},"title":"Why I Still Like Serverless for Small Teams","author":"Wade","date":"April 1, 2026","format":false,"excerpt":"Serverless has real tradeoffs, but for small teams I still think it usually wins. The operational overhead stays low, the first version ships faster, and the mistakes are easier to afford early on.","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":573,"url":"https:\/\/wade.one\/blog\/2012\/02\/05\/regular-expression-regex-for-date-part-extractionarray-split\/","url_meta":{"origin":1172,"position":4},"title":"Regular Expression (Regex) For Date part extraction\/array split","author":"Wade","date":"February 5, 2012","format":false,"excerpt":"Needed to use this recently to create a specificity parameter for an API at work, it gives you a key\/value array from an ISO date string regardless of what is actually set in the string (e.g. if you give 2011-06-07 04 you'll get an array back as array('year'=>2011, 'month' =>\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":629,"url":"https:\/\/wade.one\/blog\/2012\/10\/15\/using-amazon-ec2-with-c-net\/","url_meta":{"origin":1172,"position":5},"title":"Using Amazon EC2 with C# .net","author":"Wade","date":"October 15, 2012","format":false,"excerpt":"Amazon's EC2 platform has a very in-depth console which allows you to do a lot, but what if you want to automate some of the processes or handling servers? I've been working with EC2 a lot recently and automating server starting\/stopping based on parameters of the system we use here\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/wade.one\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/comments?post=1172"}],"version-history":[{"count":1,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1172\/revisions"}],"predecessor-version":[{"id":1196,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/posts\/1172\/revisions\/1196"}],"wp:attachment":[{"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/media?parent=1172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/categories?post=1172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wade.one\/blog\/wp-json\/wp\/v2\/tags?post=1172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}