160 lines
7.0 KiB
TypeScript
160 lines
7.0 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import Link from 'next/link'
|
|
|
|
export default function Playground() {
|
|
const [apiKey, setApiKey] = useState('')
|
|
const [url, setUrl] = useState('https://example.com')
|
|
const [endpoint, setEndpoint] = useState('screenshot')
|
|
const [options, setOptions] = useState('{}')
|
|
const [result, setResult] = useState('')
|
|
const [loading, setLoading] = useState(false)
|
|
const [codeLang, setCodeLang] = useState('curl')
|
|
|
|
const endpoints = [
|
|
{ value: 'screenshot', label: 'Screenshot' },
|
|
{ value: 'pdf', label: 'PDF' },
|
|
{ value: 'crawl', label: 'Crawl' },
|
|
{ value: 'content', label: 'Content' },
|
|
{ value: 'markdown', label: 'Markdown' },
|
|
{ value: 'json', label: 'JSON' },
|
|
{ value: 'links', label: 'Links' },
|
|
{ value: 'scrape', label: 'Scrape' },
|
|
{ value: 'snapshot', label: 'Snapshot' },
|
|
{ value: 'extract', label: 'AI Extract' },
|
|
]
|
|
|
|
async function sendRequest() {
|
|
setLoading(true)
|
|
try {
|
|
const body: any = { url }
|
|
if (options && options !== '{}') {
|
|
body.options = JSON.parse(options)
|
|
}
|
|
const res = await fetch(`http://localhost:3000/api/${endpoint}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-api-key': apiKey,
|
|
},
|
|
body: JSON.stringify(body),
|
|
})
|
|
const data = await res.json()
|
|
setResult(JSON.stringify(data, null, 2))
|
|
} catch (e) {
|
|
setResult(String(e))
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
function getCodeSnippet() {
|
|
const body = JSON.stringify({ url, options: JSON.parse(options || '{}') }, null, 2)
|
|
switch (codeLang) {
|
|
case 'curl':
|
|
return `curl -X POST http://localhost:3000/api/${endpoint} \\
|
|
-H "Content-Type: application/json" \\
|
|
-H "x-api-key: ${apiKey || 'YOUR_API_KEY'}" \\
|
|
-d '${body}'`
|
|
case 'python':
|
|
return `import requests
|
|
|
|
response = requests.post(
|
|
"http://localhost:3000/api/${endpoint}",
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"x-api-key": "${apiKey || 'YOUR_API_KEY'}"
|
|
},
|
|
json=${body.replace(/true/g, 'True').replace(/false/g, 'False').replace(/null/g, 'None')}
|
|
)
|
|
print(response.json())`
|
|
case 'javascript':
|
|
return `const response = await fetch('http://localhost:3000/api/${endpoint}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'x-api-key': '${apiKey || 'YOUR_API_KEY'}'
|
|
},
|
|
body: JSON.stringify(${body})
|
|
});
|
|
const data = await response.json();
|
|
console.log(data);`
|
|
default:
|
|
return ''
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main style={{ maxWidth: 1200, margin: '0 auto', padding: '40px 20px' }}>
|
|
<nav style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 40 }}>
|
|
<Link href="/" style={{ fontSize: 24, fontWeight: 700, color: '#fff', textDecoration: 'none' }}>Crawl API</Link>
|
|
<Link href="/" style={{ color: '#888', textDecoration: 'none' }}>← Back</Link>
|
|
</nav>
|
|
|
|
<h1 style={{ fontSize: 36, marginBottom: 8 }}>API Playground</h1>
|
|
<p style={{ color: '#888', marginBottom: 32 }}>Test any endpoint directly from the browser.</p>
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
|
|
<div>
|
|
<div style={{ background: '#111', borderRadius: 12, padding: 24, marginBottom: 24 }}>
|
|
<h3 style={{ marginTop: 0 }}>Request</h3>
|
|
<div style={{ display: 'grid', gap: 12 }}>
|
|
<div>
|
|
<label style={{ display: 'block', color: '#888', marginBottom: 4, fontSize: 13 }}>API Key</label>
|
|
<input type="text" value={apiKey} onChange={e => setApiKey(e.target.value)} placeholder="your-api-key"
|
|
style={{ width: '100%', padding: 10, background: '#1a1a1a', border: '1px solid #333', borderRadius: 6, color: '#fff', fontSize: 13, boxSizing: 'border-box' }} />
|
|
</div>
|
|
<div>
|
|
<label style={{ display: 'block', color: '#888', marginBottom: 4, fontSize: 13 }}>Endpoint</label>
|
|
<select value={endpoint} onChange={e => setEndpoint(e.target.value)}
|
|
style={{ width: '100%', padding: 10, background: '#1a1a1a', border: '1px solid #333', borderRadius: 6, color: '#fff', fontSize: 13 }}>
|
|
{endpoints.map(ep => <option key={ep.value} value={ep.value}>{ep.label}</option>)}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style={{ display: 'block', color: '#888', marginBottom: 4, fontSize: 13 }}>URL</label>
|
|
<input type="text" value={url} onChange={e => setUrl(e.target.value)}
|
|
style={{ width: '100%', padding: 10, background: '#1a1a1a', border: '1px solid #333', borderRadius: 6, color: '#fff', fontSize: 13, boxSizing: 'border-box' }} />
|
|
</div>
|
|
<div>
|
|
<label style={{ display: 'block', color: '#888', marginBottom: 4, fontSize: 13 }}>Options (JSON)</label>
|
|
<textarea value={options} onChange={e => setOptions(e.target.value)} rows={4}
|
|
style={{ width: '100%', padding: 10, background: '#1a1a1a', border: '1px solid #333', borderRadius: 6, color: '#fff', fontSize: 13, boxSizing: 'border-box', fontFamily: 'monospace' }} />
|
|
</div>
|
|
<button onClick={sendRequest} disabled={loading}
|
|
style={{ background: loading ? '#333' : '#fff', color: '#000', padding: '12px', borderRadius: 6, border: 'none', fontWeight: 600, cursor: loading ? 'not-allowed' : 'pointer' }}>
|
|
{loading ? 'Sending...' : 'Send Request'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ background: '#111', borderRadius: 12, padding: 24 }}>
|
|
<h3 style={{ marginTop: 0 }}>Code Snippet</h3>
|
|
<div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
|
|
{['curl', 'python', 'javascript'].map(l => (
|
|
<button key={l} onClick={() => setCodeLang(l)}
|
|
style={{ background: codeLang === l ? '#fff' : '#1a1a1a', color: codeLang === l ? '#000' : '#888', padding: '6px 12px', borderRadius: 4, border: 'none', fontSize: 12, cursor: 'pointer', textTransform: 'uppercase' }}>
|
|
{l}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<pre style={{ margin: 0, fontSize: 12, overflow: 'auto', background: '#0a0a0a', padding: 12, borderRadius: 6 }}>{getCodeSnippet()}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div style={{ background: '#111', borderRadius: 12, padding: 24, height: '100%' }}>
|
|
<h3 style={{ marginTop: 0 }}>Response</h3>
|
|
{result ? (
|
|
<pre style={{ margin: 0, fontSize: 13, overflow: 'auto', background: '#0a0a0a', padding: 12, borderRadius: 6, height: 'calc(100% - 40px)' }}>{result}</pre>
|
|
) : (
|
|
<div style={{ color: '#555', textAlign: 'center', padding: '40px 0' }}>Send a request to see the response</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
)
|
|
}
|