Drop this file at the repo root. Claude Code reads it automatically on every run.
n8nRequest — a minimal HTTP client web app that lets developers build and test API requests, then export them as ready-to-paste n8n HTTP Request node JSON.
The core pain: devs test in Postman/Insomnia, then manually recreate every header/body/auth inside n8n's cramped node panel. This tool bridges that gap with a single "Export → n8n" button.
Stack: Nuxt 3 + TypeScript + Tailwind CSS
Deployment target: Vercel (static/SSR)
No backend required. All requests fire directly from the browser. CORS issues are the user's problem (document it, don't solve it in v1).
Request Profile — the full configuration of an outgoing HTTP request: method, URL, headers, body, auth. This is the central data unit.
Avoid: "request object", "payload config"
Export — the act of converting a Request Profile into a valid n8n HTTP Request node JSON blob, ready to paste into n8n's JSON import.
Avoid: "serialize", "download"
n8n Node JSON — the specific JSON format n8n expects when importing a node via its JSON editor. Structure is versioned (typeVersion 4.2 as of writing).
Avoid: "n8n JSON", "workflow JSON"
Response Panel — the read-only area that displays the HTTP response: status code, timing, response body, headers.
Collection — a saved list of Request Profiles. Out of scope for v1.
When building n8n workflows, developers must configure HTTP Request nodes manually inside n8n's cramped UI. There is no way to test a request in a proper client and then transfer that configuration to n8n without manual re-entry. Headers get forgotten, body structures get mistyped, auth gets misconfigured. Every n8n HTTP node is rebuilt from scratch.
A focused HTTP client that mirrors the n8n HTTP Request node's capabilities. The user builds and tests a request in a clean UI, verifies the response, and hits "Export to n8n" to get valid node JSON they can paste directly.
- As a developer, I want to enter a URL and select an HTTP method so I can define the request target.
- As a developer, I want to add request headers as key-value pairs so I can set Content-Type, Authorization, and custom headers.
- As a developer, I want to write a JSON request body with syntax highlighting so I can build POST/PUT/PATCH payloads without typos.
- As a developer, I want to configure Bearer token auth so I can test authenticated endpoints.
- As a developer, I want to configure Basic auth (username + password) so I can test legacy authenticated APIs.
- As a developer, I want to configure API Key auth (header name + value) so I can test key-authenticated APIs.
- As a developer, I want to send the request and see the response status code, body, and timing so I can verify the API behaves as expected.
- As a developer, I want response JSON to be syntax-highlighted and pretty-printed so I can read nested structures easily.
- As a developer, I want to click "Export to n8n" and have the n8n HTTP Request node JSON copied to my clipboard so I can paste it directly into n8n.
- As a developer, I want the exported JSON to be valid n8n node format (typeVersion 4.2) so it imports without errors.
- As a developer, I want to import a cURL command and have it parsed into the request form so I can migrate existing curl commands quickly.
- As a developer, I want to see query parameters as an editable key-value table so I don't have to manually encode them in the URL.
- As a developer, I want query params I add in the table to be reflected live in the URL bar so I can see the final URL.
- As a developer, I want the UI to clearly show me which auth method is active so I don't accidentally double-configure auth.
- As a developer, I want to toggle headers on/off without deleting them so I can test with and without specific headers.
- As a developer, I want to save a request profile to localStorage so I can return to it after a page refresh.
- As a developer, I want to see a clear error message if the request fails (network error, CORS, timeout) so I understand what went wrong.
- As a developer, I want the export button to be disabled if no URL is set so I don't export empty/invalid nodes.
- As a developer, I want to choose between raw JSON body and form-urlencoded body types so I can match the API's expected content type.
- As a developer, I want the n8n export to automatically set the correct Content-Type header based on my body type so the export just works.
Central state for the active Request Profile. Owns: method, url, headers array, queryParams array, body (raw string), bodyType (json | form | none), auth config. Exposes mutators. This is the single source of truth — every panel reads from it, every export consumes it.
Wraps $fetch / native fetch. Accepts a Request Profile, fires the request, returns { status, body, headers, durationMs, error }. Completely decoupled from UI. Testable in isolation with a mock fetch adapter.
Takes a Request Profile, returns a string of valid n8n HTTP Request node JSON (typeVersion 4.2). Pure function — no side effects. This is the most important module in the app. Make it a deep module: the caller passes a profile, gets a string back, knows nothing about n8n's internal structure.
n8n HTTP Request node shape (typeVersion 4.2):
{
"parameters": {
"method": "POST",
"url": "https://api.example.com/endpoint",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "Content-Type", "value": "application/json" }
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [...]
},
"bodyContentType": "json",
"jsonBody": "{\"key\": \"value\"}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [0, 0],
"name": "HTTP Request"
}Verify the exact field names against https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/ before finalizing. The exporter must handle all auth types (none, bearer, basicAuth, apiKey in header).
Parses a curl command string into a Partial. Handles: -X METHOD, -H "Header: Value", -d 'body', --data-raw, --user user:pass, -u user:pass. Return partial — caller merges into active profile.
Reusable table component for headers and query params. Props: rows, onUpdate. Each row: { key, value, enabled: boolean }. Renders as an editable grid with an enable/disable toggle per row and a delete button. Used for both headers and query params panels.
Read-only. Displays: status badge (color-coded), duration in ms, response body with syntax highlighting (use shiki or highlight.js), response headers in a collapsible table.
Single page app. No routing needed in v1. Everything lives on /.
Two-column on desktop: left = request builder (method + URL bar, tabs for Params / Headers / Body / Auth), right = response panel. Single column on mobile (builder on top, response below).
On every Request Profile change, debounce-save to localStorage key n8nrequest_profile. On app mount, rehydrate from localStorage if present.
Document clearly in the UI: "Requests fire from your browser. CORS errors are enforced by the target server." Do not proxy. Do not solve this in v1.
Use navigator.clipboard.writeText() for the export copy. Show a transient "Copied!" confirmation on the export button (500ms, then revert).
/
├── CLAUDE.md ← this file
├── nuxt.config.ts
├── app.vue
├── pages/
│ └── index.vue ← main app page
├── components/
│ ├── RequestBuilder.vue ← left panel container
│ ├── KeyValueEditor.vue ← reusable key/value table
│ ├── BodyEditor.vue ← JSON/form body editor
│ ├── AuthEditor.vue ← auth method selector + fields
│ ├── ResponsePanel.vue ← right panel, read-only
│ ├── ExportButton.vue ← export to n8n + copy logic
│ └── CurlImportModal.vue ← paste curl → parse → populate
├── composables/
│ ├── useRequestProfile.ts ← central request state
│ └── useHttpSender.ts ← fires the request
├── utils/
│ ├── n8nExporter.ts ← Request Profile → n8n node JSON
│ └── curlParser.ts ← curl string → Partial<RequestProfile>
├── types/
│ └── index.ts ← RequestProfile, AuthConfig, etc.
└── tests/
├── n8nExporter.test.ts
└── curlParser.test.ts
Test behavior through public interfaces. The two pure utility modules are the highest-value test targets — they have no side effects and encode the most critical logic.
n8nExporter.ts — HIGH PRIORITY
- Given a GET request with no body and no auth → produces valid n8n JSON with
sendBody: false - Given a POST with JSON body →
bodyContentTypeis"json",jsonBodyis set - Given Bearer auth →
authenticationandgenericAuthTypeare set correctly - Given Basic auth → maps to n8n's expected basicAuth fields
- Given API Key auth → maps to header auth fields
- Given disabled headers → they are excluded from the export
- Given query params → they are included in the URL or as n8n queryParameters array
curlParser.ts — HIGH PRIORITY
curl https://api.example.com→ method GET, url setcurl -X POST -H "Content-Type: application/json" -d '{"k":"v"}' https://...→ POST, header set, body setcurl -u user:pass https://...→ Basic auth populated- Malformed curl → returns empty partial, no throw
useHttpSender — NOT unit tested (hits network; integration test or manual QA only)
Vitest. Tests live in /tests/. Run with pnpm test.
- Collections / saved request history (beyond single localStorage slot)
- Environments / variables (e.g.
{{BASE_URL}}) - WebSocket / GraphQL / gRPC support
- Response diffing
- Team sharing
- OAuth2 flow (only static token)
- Mosh or any non-HTTP protocol
- Backend proxy for CORS bypass
- n8n workflow export (multi-node) — single node only
Follow this order — each slice is demoable on its own:
- Scaffold — Nuxt 3 + Tailwind + TypeScript. Empty two-column layout renders.
- Request form — URL bar + method dropdown + send button. No real request yet.
useRequestProfilecomposable — wires form to central state.useHttpSendercomposable — fires real requests, returns response data.ResponsePanelcomponent — displays status + body. End-to-end: type URL, hit send, see response.KeyValueEditorcomponent — headers + query params tabs working.BodyEditorcomponent — raw JSON body tab, body type selector.AuthEditorcomponent — Bearer / Basic / API Key auth tabs.n8nExporterutility + tests — pure function, fully tested.ExportButtoncomponent — calls exporter, copies to clipboard, shows confirmation.curlParserutility + tests — pure function, fully tested.CurlImportModal— paste curl, parse, populate form.- localStorage persistence — rehydrate on mount, save on change.
- Polish — CORS error messaging, disabled states, mobile layout, loading states.
Local markdown — issues live as files under .scratch/.
| Role | Label string |
|---|---|
| needs-triage | needs-triage |
| needs-info | needs-info |
| ready-for-agent | ready-for-agent |
| ready-for-human | ready-for-human |
| wontfix | wontfix |
Single-context. CONTEXT.md at repo root (create if absent). ADRs in docs/adr/.
- Keep the n8n node typeVersion as a named constant (
N8N_HTTP_NODE_VERSION = 4.2) in the exporter so it's easy to bump when n8n releases a new version. - The
positionfield in the exported JSON can be hardcoded to[0, 0]— n8n repositions nodes on paste. - If
navigator.clipboardis unavailable (HTTP context), fall back to a<textarea>select +document.execCommand('copy')with a visible fallback textarea. - For syntax highlighting in the response panel, prefer
shiki(Nuxt has a first-class integration via@nuxtjs/mdcor standalone) over highlight.js — smaller, tree-shakeable, and supports more themes. - Auth fields should be masked (password-type inputs) to avoid shoulder surfing.
- The export modal (or inline preview) should show the raw JSON before copying so the user can verify it — trust but verify.