<?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>Forem: Mohamed Rayen Bouzaabia</title>
    <description>The latest articles on Forem by Mohamed Rayen Bouzaabia (@mohamedrayenbouzaabiaaxelites).</description>
    <link>https://forem.com/mohamedrayenbouzaabiaaxelites</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%2F3515642%2Fd5acbff5-e41e-4d60-9466-5452c6a34295.jpeg</url>
      <title>Forem: Mohamed Rayen Bouzaabia</title>
      <link>https://forem.com/mohamedrayenbouzaabiaaxelites</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mohamedrayenbouzaabiaaxelites"/>
    <language>en</language>
    <item>
      <title>A Polished, Read‑Only Cloudflare D1 Explorer (Express + Vanilla JS)</title>
      <dc:creator>Mohamed Rayen Bouzaabia</dc:creator>
      <pubDate>Fri, 19 Sep 2025 13:29:56 +0000</pubDate>
      <link>https://forem.com/mohamedrayenbouzaabiaaxelites/a-polished-read-only-cloudflare-d1-explorer-express-vanilla-js-55jf</link>
      <guid>https://forem.com/mohamedrayenbouzaabiaaxelites/a-polished-read-only-cloudflare-d1-explorer-express-vanilla-js-55jf</guid>
      <description>&lt;p&gt;If you’ve ever wanted a lightweight UI to explore your Cloudflare D1 data without pulling in a heavy admin tool or writing ad‑hoc scripts every time, this project is for you. It’s an Express + vanilla JS UI that talks to the Cloudflare v4 API and enforces read‑only queries for safety.&lt;/p&gt;

&lt;p&gt;Why this approach?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No client frameworks or build steps — easy to run and tweak.&lt;/li&gt;
&lt;li&gt;Read‑only by design — only single &lt;code&gt;SELECT&lt;/code&gt;/&lt;code&gt;WITH&lt;/code&gt; statements are allowed.&lt;/li&gt;
&lt;li&gt;Professional UX — responsive layout, sidebar table list, sortable results, and light/dark theme.&lt;/li&gt;
&lt;li&gt;Shareable state — the UI syncs to URL params so you can refresh or send a link to the exact view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Highlights&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sidebar table list with search (excludes internal/underscore tables like &lt;code&gt;_cf_*&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Browse panel to pick columns, add filters, set sort/limit/offset.&lt;/li&gt;
&lt;li&gt;Click any header to toggle ASC/DESC sorting.&lt;/li&gt;
&lt;li&gt;SQL editor for custom single‐statement queries.&lt;/li&gt;
&lt;li&gt;Settings modal to manage &lt;code&gt;.env&lt;/code&gt; credentials from the UI.&lt;/li&gt;
&lt;li&gt;Light/Dark theme toggle with persistence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshots&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknaunfjdovmrtd7ytmae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknaunfjdovmrtd7ytmae.png" alt="dark mode" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxyyr2hhx40xwkitvhell.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxyyr2hhx40xwkitvhell.png" alt="bright mode" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6lgcoeqnpq4rrcy0r6uf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6lgcoeqnpq4rrcy0r6uf.png" alt="SQL" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca9ckuidarzu6qtv8491.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca9ckuidarzu6qtv8491.png" alt="Settings" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting started&lt;br&gt;
1) Clone the repo and install deps&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/mohamedrayenbouzaabia-axelites/cloudflare_d1_interface.git
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Run it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev   # nodemon
# or
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3) Open &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; and set your Cloudflare credentials in the Settings panel (it writes &lt;code&gt;.env&lt;/code&gt; for you).&lt;/p&gt;

&lt;p&gt;Configuration&lt;br&gt;
&lt;code&gt;.env&lt;/code&gt; supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CF_ACCOUNT_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CF_D1_DATABASE_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CF_API_TOKEN&lt;/code&gt; (D1 Data Access is enough)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CF_API_BASE&lt;/code&gt; (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server removes comments, rejects multi‐statement SQL, and only accepts single &lt;code&gt;SELECT&lt;/code&gt;/&lt;code&gt;WITH&lt;/code&gt; queries.&lt;/li&gt;
&lt;li&gt;Tokens never leave the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Express serves &lt;code&gt;/public&lt;/code&gt; and exposes APIs:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /api/query&lt;/code&gt; (read‑only guard)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /api/tables&lt;/code&gt;, &lt;code&gt;GET /api/columns?table=...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET/POST /api/env-config&lt;/code&gt; for &lt;code&gt;.env&lt;/code&gt; management&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The UI is vanilla JS that syncs most state into URL params.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;What’s next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Export CSV&lt;/li&gt;
&lt;li&gt;Keyboard navigation and shortcuts&lt;/li&gt;
&lt;li&gt;Saved views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’d like to try it or contribute, grab the repo and let me know what would make it more useful for your team!&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>node</category>
      <category>webdev</category>
      <category>database</category>
    </item>
  </channel>
</rss>
