<?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: Kotaro Takaoka</title>
    <description>The latest articles on DEV Community by Kotaro Takaoka (@kotaro_takaoka_34b3ca03d2).</description>
    <link>https://dev.to/kotaro_takaoka_34b3ca03d2</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3849516%2Ff54be99a-c9c9-4b47-aa72-32b73b559cc5.png</url>
      <title>DEV Community: Kotaro Takaoka</title>
      <link>https://dev.to/kotaro_takaoka_34b3ca03d2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kotaro_takaoka_34b3ca03d2"/>
    <language>en</language>
    <item>
      <title>Stop writing TypeScript interfaces by hand — convert JSON automatically</title>
      <dc:creator>Kotaro Takaoka</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:47:15 +0000</pubDate>
      <link>https://dev.to/kotaro_takaoka_34b3ca03d2/stop-writing-typescript-interfaces-by-hand-convert-json-automatically-588m</link>
      <guid>https://dev.to/kotaro_takaoka_34b3ca03d2/stop-writing-typescript-interfaces-by-hand-convert-json-automatically-588m</guid>
      <description>&lt;p&gt;How many times have you received a JSON response from an API and had to manually write TypeScript interfaces for it?&lt;/p&gt;

&lt;p&gt;I built a free tool that does it instantly: &lt;a href="https://snapapi.akokoa1221.workers.dev/tools/json-to-typescript" rel="noopener noreferrer"&gt;JSON to TypeScript Converter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Paste this JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alice@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123 Main St"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Springfield"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"zip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"62701"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;29.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get this TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;OrdersItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OrdersItem&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nested objects (creates separate interfaces)&lt;/li&gt;
&lt;li&gt;Arrays (infers element types)&lt;/li&gt;
&lt;li&gt;Mixed types (&lt;code&gt;string | number&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Null values (&lt;code&gt;unknown&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;I was building &lt;a href="https://snapapi.akokoa1221.workers.dev" rel="noopener noreferrer"&gt;SnapAPI&lt;/a&gt; — a tool that creates instant REST APIs from JSON — and kept needing to convert API responses to TypeScript. So I built the converter as a standalone tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other free tools
&lt;/h2&gt;

&lt;p&gt;While I was at it, I built a few more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://snapapi.akokoa1221.workers.dev/tools/json-formatter" rel="noopener noreferrer"&gt;JSON Formatter&lt;/a&gt; — Beautify and minify JSON&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://snapapi.akokoa1221.workers.dev/tools/json-validator" rel="noopener noreferrer"&gt;JSON Validator&lt;/a&gt; — Real-time syntax validation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://snapapi.akokoa1221.workers.dev/tools/fake-data-generator" rel="noopener noreferrer"&gt;Fake Data Generator&lt;/a&gt; — Generate realistic test data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All free, no signup, open source: &lt;a href="https://github.com/ko-tarou/snapapi" rel="noopener noreferrer"&gt;github.com/ko-tarou/snapapi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I got mass-rate-limited by my own API on the day of our demo</title>
      <dc:creator>Kotaro Takaoka</dc:creator>
      <pubDate>Sun, 29 Mar 2026 15:01:34 +0000</pubDate>
      <link>https://dev.to/kotaro_takaoka_34b3ca03d2/i-built-a-tool-that-turns-json-into-a-rest-api-in-5-seconds-16i1</link>
      <guid>https://dev.to/kotaro_takaoka_34b3ca03d2/i-built-a-tool-that-turns-json-into-a-rest-api-in-5-seconds-16i1</guid>
      <description>&lt;p&gt;Last week I was building a dashboard for a client. The backend wasn't ready. I had a week of frontend work planned, and the API endpoints I needed didn't exist yet.&lt;/p&gt;

&lt;p&gt;I've been in this situation a dozen times. Usually I just hardcode some JSON and move on. But this time I needed the full flow working for a stakeholder demo on Friday. GET, POST, DELETE, the whole thing. Hardcoded JSON wasn't going to cut it.&lt;/p&gt;

&lt;p&gt;So I spent that evening building a thing I've wanted for years: drop a JSON file, get a working REST API back. I called it SnapAPI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;You give it JSON. It gives you endpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://snapapi.akokoa1221.workers.dev/api/mock &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get back a URL. That URL supports GET, POST, PUT, DELETE. Data persists for 24 hours. CORS works from anywhere. No account, no setup.&lt;/p&gt;

&lt;p&gt;I used it for the demo. It worked. The stakeholders didn't know they were looking at mock data. That felt good.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing I didn't expect to need
&lt;/h2&gt;

&lt;p&gt;After the demo I kept using it. And I kept running into the same annoyance: writing sample data by hand is tedious. Ten users with realistic names and emails? That's 30 minutes of copy-pasting from a faker library.&lt;/p&gt;

&lt;p&gt;So I added a schema-based generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://snapapi.akokoa1221.workers.dev/api/mock &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"_generate": {"users": {"count": 50, "schema": {"id": "autoincrement", "name": "name", "email": "email", "age": "number:22-45"}}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;50 users. Realistic names. Done. No external dependencies, it's all rule-based generation built in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rate-limit incident
&lt;/h2&gt;

&lt;p&gt;Here's where I messed up. I was load-testing my own dashboard against SnapAPI and forgot I had added rate limiting (10 requests per minute for endpoint creation). Locked myself out of my own tool during a live coding session.&lt;/p&gt;

&lt;p&gt;Lessons learned: eat your own dogfood, but maybe whitelist yourself first.&lt;/p&gt;

&lt;p&gt;I also added response delay simulation after this, because I realized I'd never tested what my dashboard does when an API takes 3 seconds to respond. Turns out it didn't handle it well. The &lt;code&gt;_config&lt;/code&gt; option lets you add artificial latency and random errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"delay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"errorRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"errorStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every request to that endpoint now takes 2 seconds and fails 20% of the time. My dashboard handles it gracefully now. Mostly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's under the hood
&lt;/h2&gt;

&lt;p&gt;Next.js 16 running on Cloudflare Pages. D1 for storage (SQLite at the edge, which is kind of wild). The whole thing costs me $0/month.&lt;/p&gt;

&lt;p&gt;I also built a CLI because I live in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx snapapi-cli create data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source is on GitHub if you want to poke around: &lt;a href="https://github.com/ko-tarou/snapapi" rel="noopener noreferrer"&gt;github.com/ko-tarou/snapapi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thing I'm least happy with is the landing page design. I'm not a designer. If you visit &lt;a href="https://snapapi.akokoa1221.workers.dev" rel="noopener noreferrer"&gt;snapapi.akokoa1221.workers.dev&lt;/a&gt; and think 'wow this looks bad', yeah, I know. PRs welcome.&lt;/p&gt;

&lt;p&gt;I'd love to hear if this is useful to anyone else, or if I'm just solving my own very specific problem.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
