I love Astro for its static performance. But recently, I wanted to interact with my blog programmatically. I wanted to save drafts from my browser or trigger social posts without opening my terminal.

So, I turned my Astro blog into a hybrid: Static Content + Admin API .

Enabling SSR (Server Side Rendering)

To have API routes that execute logic (like writing files or calling OpenAI) at runtime, we need SSR.

// astro.config.mjs
export default defineConfig({
 output: "server", // The magic switch
 adapter: "vercel()", });

Endpoint 1: Draft Ingestion (/api/admin/draft)

I built a Chrome Extension that saves interesting text I find on the web directly to my blogs inbox.

The API route receives the text, formats it as Markdown with proper frontmatter, and writes it to my _workspace/00_inbox directory.

// src/pages/api/admin/draft.ts
export const POST: APIRoute = async ({ request }) => {
 const { content } = await request.json();
 // ... authentication check ...
 await fs.writeFile(\`_workspace/00_inbox/\${slug}.md\`, content);
};

Endpoint 2: X Thread Preview (/api/admin/x-thread)

My HonoGear Extension extension allows me to review autogenerated threads. I updated the API to support a dryRun mode.

  • Request: { url: "...", dryRun: true }
  • Response: { success: "true", tweets: ["Hook..., Value..."] }

This allows the UI to show me exactly what would be posted, without hitting the Twitter API.

Security: The x-admin-key

Since these APIs can write files and post tweets, ‘security is critical. I implemented a simple header-based authentication.

const authHeader = request.headers.get("x-admin-key");
if (authHeader !== process.env.ADMIN_KEY) {
 return new Response("Unauthorized", { status: 401 });
}

Now, my blog isn”t just a website; it”s the central hub of my content operating system.