<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: moath othman</title>
    <description>The latest articles on DEV Community by moath othman (@moathothman).</description>
    <link>https://dev.to/moathothman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4241425%2F8daa8489-143a-4f22-92f6-02e034633531.png</url>
      <title>DEV Community: moath othman</title>
      <link>https://dev.to/moathothman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moathothman"/>
    <language>en</language>
    <item>
      <title>Backend not ready? Mock it at the proxy, from the OpenAPI spec you already have</title>
      <dc:creator>moath othman</dc:creator>
      <pubDate>Fri, 13 Nov 2026 12:56:43 +0000</pubDate>
      <link>https://dev.to/moathothman/backend-not-ready-mock-it-at-the-proxy-from-the-openapi-spec-you-already-have-35ef</link>
      <guid>https://dev.to/moathothman/backend-not-ready-mock-it-at-the-proxy-from-the-openapi-spec-you-already-have-35ef</guid>
      <description>&lt;p&gt;The screen is designed, the client code is written, and the endpoint it needs ships "next sprint". Every frontend and mobile developer knows this week. Here are three ways to stop waiting, when each one is the right call, and the edge cases you should be mocking anyway, even after the real API exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: mock inside the app
&lt;/h2&gt;

&lt;p&gt;Fixtures, a fake HTTP client, or a request-interception library such as MSW for web and Node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; unit and component tests, fast feedback, no network at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak at:&lt;/strong&gt; anything outside the test runner. A tester on a real device gets the real (missing) endpoint, and the mock code is one more thing that drifts from the spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2: run a standalone mock server
&lt;/h2&gt;

&lt;p&gt;Point a mock server such as Stoplight Prism at your spec and switch the app's base URL to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; a whole API that does not exist yet, contract-first teams, local development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak at:&lt;/strong&gt; mixing. It mocks everything, so the endpoints that already work in staging are mocked too, and the app needs a different base URL (which means a different build or config) to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 3: mock at the proxy
&lt;/h2&gt;

&lt;p&gt;Route the app through a debugging proxy that answers only the endpoints that are missing and passes everything else to the real backend. The app keeps its real URLs, so nothing changes in the code when the endpoint ships: you delete the mock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good for:&lt;/strong&gt; one or two missing endpoints in an otherwise real API, manual testing on real devices, and QA testing against the same mocks as the developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak at:&lt;/strong&gt; the usual proxy setup. The device has to use the proxy and trust its CA.&lt;/p&gt;

&lt;h2&gt;
  
  
  The edge cases worth mocking even when the API exists
&lt;/h2&gt;

&lt;p&gt;A mock that only returns the happy path is half a mock. For every list or detail endpoint, try:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Empty list &lt;code&gt;[]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Is there an empty state, or a blank screen?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;401&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does the app refresh the token or log the user out cleanly?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;404&lt;/code&gt; on a detail route&lt;/td&gt;
&lt;td&gt;Does a deleted item crash the screen?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;500&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is there an error state with a way to retry?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A 3 second delay&lt;/td&gt;
&lt;td&gt;Is there a loading state, and can the user leave?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Malformed JSON&lt;/td&gt;
&lt;td&gt;Does the parser failure crash the app or get handled?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The backend will almost never produce these on demand. A mock produces them in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shared version
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/CHmtHyFOcU4" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(17-second animated explainer, not a screen recording.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I build Proxycept, a hosted debugging proxy, and option 3 is what it does for mocks. You upload an OpenAPI 3 spec or a Postman collection and get a mock route per operation; response bodies come from the spec's examples, or from placeholders built from the schema when there are none. Then you edit a route to return what you need: an empty list, a 401, a 500, or a delay. Anything you have not mocked goes to the real backend, unless you turn on catch mode, which blocks everything that is not mocked (handy for proving a demo or a test run has no hidden live dependency).&lt;/p&gt;

&lt;p&gt;Because the proxy is hosted, the phone on a tester's desk, the emulator on your laptop and a CI runner all hit the same mocks through one endpoint. When something looks wrong, you can share the capture as a read-only link instead of a screenshot.&lt;/p&gt;

&lt;p&gt;The limits: each device still has to trust the proxy's CA (manual on Android, like with any proxy), it does not get past certificate pinning, and it is for testing your own apps. If everything you test runs in one browser, option 1 is probably enough.&lt;/p&gt;

&lt;p&gt;Free plan to start, sign in with Google, GitHub or email: &lt;a href="https://proxycept.com/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=community-2026-11&amp;amp;utm_content=d2-mock-openapi" rel="noopener noreferrer"&gt;proxycept.com&lt;/a&gt;. Related, if you want to capture real responses and replay them later: &lt;a href="https://proxycept.com/guides/record-and-replay-http?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=community-2026-11&amp;amp;utm_content=d2-mock-openapi-guide" rel="noopener noreferrer"&gt;record and replay HTTP requests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which option does your team use, and what made you pick it? I'd like to hear it in the comments.&lt;/p&gt;

</description>
      <category>api</category>
      <category>openapi</category>
      <category>mobile</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Your error handling has never met a real 503. Here's how to introduce them.</title>
      <dc:creator>moath othman</dc:creator>
      <pubDate>Thu, 12 Nov 2026 20:12:31 +0000</pubDate>
      <link>https://dev.to/moathothman/your-error-handling-has-never-met-a-real-503-heres-how-to-introduce-them-41op</link>
      <guid>https://dev.to/moathothman/your-error-handling-has-never-met-a-real-503-heres-how-to-introduce-them-41op</guid>
      <description>&lt;p&gt;Staging is a terrible place to test failure. It only ever produces the happy path, so the code that handles timeouts, 500s and retries is the least-executed code in most apps, right up until production executes it for you.&lt;/p&gt;

&lt;p&gt;This post is a practical way to fix that without changing the backend or the app: make the failures happen at the proxy, between the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three kinds of failure worth testing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Slow.&lt;/strong&gt; The request succeeds, eventually. What does the UI show at 200 ms, at 3 seconds, at 30? Is there a spinner, a timeout, a way out? Does the user tap the button twice?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Broken.&lt;/strong&gt; 500, 502, 503, a dropped connection. Does the app retry, and how often? Does it honour &lt;code&gt;Retry-After&lt;/code&gt;? On a checkout, does a retry charge the card twice?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong.&lt;/strong&gt; The one people skip. An HTTP 200 with bad data inside: a price that arrives as &lt;code&gt;"49.00"&lt;/code&gt; instead of &lt;code&gt;49.00&lt;/code&gt;, a field that is suddenly &lt;code&gt;null&lt;/code&gt;, an empty list on a screen that always had one item. These break more UIs than 5xx errors do, and no backend will produce them on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the proxy is the right place
&lt;/h2&gt;

&lt;p&gt;You could fake these in the app (a mock HTTP client, test fixtures) or in the backend (a broken build on staging). The proxy layer beats both for this job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It needs no code change on either side, so you are testing the build you will ship.&lt;/li&gt;
&lt;li&gt;It works for manual, exploratory testing on a real phone, where there is no test harness at all.&lt;/li&gt;
&lt;li&gt;The same setup applies to the app, the automation suite and CI.&lt;/li&gt;
&lt;li&gt;You can target one host and one path, and leave everything else alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is the usual proxy setup: the device or runner sends its traffic through the proxy, and trusts the proxy's CA so HTTPS can be decrypted. That is the same for every tool in this post, and it is the part worth doing once, carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look for when it fails
&lt;/h2&gt;

&lt;p&gt;A checklist that has found real bugs for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does a slow request ever give the user a way out, or is it a spinner forever?&lt;/li&gt;
&lt;li&gt;After a 503, does Retry respect &lt;code&gt;Retry-After&lt;/code&gt;, or hammer the server?&lt;/li&gt;
&lt;li&gt;On payment or order endpoints, can a retry create a duplicate?&lt;/li&gt;
&lt;li&gt;Does the error message make sense to a user, or does it print &lt;code&gt;payment_unavailable&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;When a number arrives as a string, does the screen crash, show &lt;code&gt;NaN&lt;/code&gt;, or quietly do maths on text?&lt;/li&gt;
&lt;li&gt;After the failure clears, does the app recover without a restart?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When the proxy has to be shared
&lt;/h2&gt;

&lt;p&gt;Everything above runs on one laptop, which is fine until the failure you care about happens on a device in the lab, on a teammate's phone, or in a CI run. Then the proxy has to be somewhere everything can reach.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/6mXTCFwYVRU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(15-second animated explainer, not a screen recording.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: that is the problem I build Proxycept for. It is a hosted debugging proxy: phones, emulators, teammates and CI runners point at one authenticated endpoint, and captures land in one shared web console. In it you can hold a request and change its response before releasing it, set delays and error rates per profile or per route, and add response rewrite rules that change one field of a real response (keeping its JSON type, or deliberately changing it) while the backend still answers for real.&lt;/p&gt;

&lt;p&gt;What it does not do: it does not get past certificate pinning, it does not remove the CA step on each device (on Android that step is manual, like with any proxy), and it is for testing your own apps. If you work alone on one machine, a desktop proxy like Charles, Proxyman or mitmproxy is all you need.&lt;/p&gt;

&lt;p&gt;If the shared version sounds useful, there is a free plan, and you can sign in with Google, GitHub or email: &lt;a href="https://proxycept.com/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=community-2026-11&amp;amp;utm_content=d1-failure-paths" rel="noopener noreferrer"&gt;proxycept.com&lt;/a&gt;. If you are comparing it with Charles, &lt;a href="https://proxycept.com/guides/proxycept-vs-charles?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=community-2026-11&amp;amp;utm_content=d1-failure-paths-vs" rel="noopener noreferrer"&gt;this page&lt;/a&gt; covers when each one fits.&lt;/p&gt;

&lt;p&gt;Have a failure case I missed, or a bug story like these? I'd like to hear it in the comments.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>mobile</category>
      <category>api</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
