Skip to content

Commit d3acbba

Browse files
feat: add interactive Try It panel to API docs (#19)
* feat: add interactive Try It panel to API docs * chore: remove unrelated changes * feat: improve Try It Out panel and docs
1 parent 63d271a commit d3acbba

2 files changed

Lines changed: 142 additions & 0 deletions

File tree

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { useState } from "react";
2+
3+
export default function TryItPanel({ endpoint, method = "POST" }) {
4+
const [apiKey, setApiKey] = useState("");
5+
const [jsonBody, setJsonBody] = useState(`{}`);
6+
const [response, setResponse] = useState("");
7+
const [status, setStatus] = useState("");
8+
const [error, setError] = useState("");
9+
const [params, setParams] = useState({});
10+
11+
function buildEndpoint() {
12+
let url = endpoint;
13+
Object.keys(params).forEach(key => {
14+
url = url.replace(`:${key}`, params[key]);
15+
});
16+
return url;
17+
}
18+
19+
20+
async function sendRequest() {
21+
// Stop if API key is missing
22+
if (!apiKey || apiKey.trim() === "") {
23+
setError("You need an API key. Go to Dashboard → Create Project → Copy API key.");
24+
return;
25+
}
26+
27+
// Clear previous error
28+
setError("");
29+
30+
try {
31+
const res = await fetch(`https://api.urbackend.bitbros.in${buildEndpoint()}`, {
32+
33+
34+
35+
method,
36+
headers: {
37+
"Content-Type": "application/json",
38+
"x-api-key": apiKey,
39+
},
40+
body: method !== "GET" ? jsonBody : null,
41+
});
42+
43+
const data = await res.text();
44+
setStatus(res.status);
45+
setResponse(data);
46+
} catch (err) {
47+
setResponse(err.message);
48+
}
49+
}
50+
51+
return (
52+
<div className="card" style={{ marginTop: "1.5rem" }}>
53+
<h4 style={{ fontSize: "0.9rem", marginBottom: "1rem", color: "var(--color-text-muted)" }}>
54+
Try It Out
55+
</h4>
56+
57+
<div style={{ marginBottom: "1rem" }}>
58+
<label className="form-label">x-api-key</label>
59+
<input
60+
className="input-field"
61+
value={apiKey}
62+
onChange={(e) => setApiKey(e.target.value)}
63+
placeholder="YOUR API KEY"
64+
/>
65+
</div>
66+
{endpoint.includes(":") && (
67+
<div style={{ marginBottom: "1rem" }}>
68+
<label className="form-label">Path Parameters</label>
69+
70+
{endpoint
71+
.match(/:([a-zA-Z0-9_]+)/g)
72+
?.map(p => {
73+
const key = p.replace(":", "");
74+
return (
75+
<input
76+
key={key}
77+
className="input-field"
78+
placeholder={key}
79+
value={params[key] || ""}
80+
onChange={e => setParams({ ...params, [key]: e.target.value })}
81+
style={{ marginBottom: "0.5rem" }}
82+
/>
83+
);
84+
})}
85+
</div>
86+
)}
87+
88+
{method !== "GET" && (
89+
<div style={{ marginBottom: "1rem" }}>
90+
<label className="form-label">Request Body</label>
91+
<textarea
92+
className="input-field"
93+
style={{ minHeight: "120px", fontFamily: "monospace" }}
94+
value={jsonBody}
95+
onChange={(e) => setJsonBody(e.target.value)}
96+
/>
97+
</div>
98+
)}
99+
100+
{error && (
101+
<div style={{
102+
background: "rgba(239,68,68,0.1)",
103+
border: "1px solid rgba(239,68,68,0.4)",
104+
padding: "0.75rem",
105+
borderRadius: "6px",
106+
color: "#f87171",
107+
marginBottom: "1rem",
108+
fontSize: "0.85rem"
109+
}}>
110+
{error}
111+
</div>
112+
)}
113+
114+
<button onClick={sendRequest} className="btn btn-primary">
115+
Send Request
116+
</button>
117+
118+
{response && (
119+
<div style={{ marginTop: "1rem" }}>
120+
<div style={{ fontSize: "0.8rem", color: "var(--color-text-muted)", marginBottom: "0.25rem" }}>
121+
Status: {status}
122+
</div>
123+
<pre style={{
124+
background: "#0b0b0b",
125+
border: "1px solid #222",
126+
borderRadius: "6px",
127+
padding: "1rem",
128+
color: "var(--color-primary)",
129+
fontSize: "0.8rem",
130+
overflowX: "auto"
131+
}}>
132+
{response}
133+
</pre>
134+
</div>
135+
)}
136+
</div>
137+
);
138+
139+
}

frontend/src/pages/Docs.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState } from 'react';
22
import { Copy, Terminal, Database, Shield, HardDrive, Check, Server, Menu, X, ChevronDown, AlertCircle, Zap, AlertTriangle } from 'lucide-react';
33
import { API_URL } from '../config';
4+
import TryItPanel from "../components/TryItPanel.jsx";
45

56
import Footer from '../components/Layout/Footer';
67

@@ -296,6 +297,8 @@ console.log(data);
296297
body={{ name: "MacBook Pro", price: 1299, inStock: true }}
297298
comment="Add a new item"
298299
/>
300+
<TryItPanel endpoint="/api/data/:collectionName" method="POST" />
301+
299302

300303
<h3 style={{ fontSize: '1.1rem', marginTop: '2rem' }}>3. Get / Update / Delete by ID</h3>
301304
<p style={{ fontSize: '0.9rem', color: 'var(--color-text-muted)' }}>

0 commit comments

Comments
 (0)