<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenSearch API - Interactive Playground</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
header {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
margin-bottom: 20px;
}
h1 { color: #667eea; }
.playground {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.panel {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
select, input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 5px;
}
textarea {
width: 100%;
height: 400px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-family: 'Fira Code', monospace;
font-size: 14px;
}
button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-weight: 600;
}
button:hover {
transform: translateY(-2px);
}
.response {
background: #f8f9fa;
border-radius: 5px;
padding: 15px;
margin-top: 15px;
white-space: pre-wrap;
font-family: 'Fira Code', monospace;
font-size: 14px;
max-height: 500px;
overflow-y: auto;
}
.status {
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
font-weight: 600;
}
.status.success { background: #d4edda; color: #155724; }
.status.error { background: #f8d7da; color: #721c24; }
.examples {
margin-top: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 10px;
}
.example-btn {
background: #6c757d;
color: white;
border: none;
padding: 5px 10px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
font-size: 12px;
}
.example-btn:hover {
background: #5a6268;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🎮 API Playground</h1>
<p>Teste interativo da OpenSearch API</p>
</header>
<div class="playground">
<div class="panel">
<h3>Request</h3>
<div class="controls">
<select id="method">
<option>GET</option>
<option>POST</option>
<option>PUT</option>
<option>DELETE</option>
</select>
<input type="text" id="endpoint" placeholder="/search/logs-*?q=error" style="flex: 1;">
<button onclick="sendRequest()">Send</button>
</div>
<textarea id="body" placeholder="Request body (JSON)...">{
"query": {
"match": {
"level": "ERROR"
}
}
}</textarea>
<div class="controls">
<input type="text" id="apikey" placeholder="API Key: sk_live_..." style="flex: 1;">
</div>
<div class="examples">
<h4>Exemplos Rápidos:</h4>
<button class="example-btn" onclick="loadExample('search_logs')">Buscar Logs</button>
<button class="example-btn" onclick="loadExample('send_metrics')">Enviar Métricas</button>
<button class="example-btn" onclick="loadExample('trace')">Enviar Trace</button>
<button class="example-btn" onclick="loadExample('vector_search')">Busca Vetorial</button>
</div>
</div>
<div class="panel">
<h3>Response</h3>
<div id="status"></div>
<div id="response" class="response">Response will appear here...</div>
</div>
</div>
</div>
<script>
const examples = {
search_logs: {
method: 'GET',
endpoint: '/search/logs-*?q=level:ERROR&size=10',
body: ''
},
send_metrics: {
method: 'POST',
endpoint: '/index/metrics-api-2024.01.01',
body: JSON.stringify({
"@timestamp": new Date().toISOString(),
"service": "test-api",
"metrics": {
"cpu": {
"usage_percent": 45.2
},
"memory": {
"used_mb": 3200,
"total_mb": 8192
}
}
}, null, 2)
},
trace: {
method: 'POST',
endpoint: '/index/traces-api-2024.01.01',
body: JSON.stringify({
"@timestamp": new Date().toISOString(),
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"operation_name": "test.operation",
"service": "test-api",
"duration_ms": 123
}, null, 2)
},
vector_search: {
method: 'POST',
endpoint: '/_search/vectors-*',
body: JSON.stringify({
"size": 10,
"query": {
"knn": {
"embedding.vector": {
"vector": [0.1, 0.2, 0.3],
"k": 10
}
}
}
}, null, 2)
}
};
function loadExample(name) {
const example = examples[name];
document.getElementById('method').value = example.method;
document.getElementById('endpoint').value = example.endpoint;
document.getElementById('body').value = example.body;
}
async function sendRequest() {
const method = document.getElementById('method').value;
const endpoint = document.getElementById('endpoint').value;
const body = document.getElementById('body').value;
const apikey = document.getElementById('apikey').value;
const options = {
method: method,
headers: {
'X-API-Key': apikey,
'Content-Type': 'application/json'
}
};
if (method !== 'GET' && body) {
try {
JSON.parse(body); options.body = body;
} catch (e) {
document.getElementById('status').innerHTML =
'<span class="status error">Invalid JSON</span>';
document.getElementById('response').textContent =
'Error: Invalid JSON in request body\n' + e.message;
return;
}
}
try {
const baseUrl = window.location.origin;
const response = await fetch(baseUrl + endpoint, options);
const contentType = response.headers.get('content-type');
let data;
if (contentType && contentType.includes('application/json')) {
data = await response.json();
} else {
data = await response.text();
}
document.getElementById('status').innerHTML =
`<span class="status ${response.ok ? 'success' : 'error'}">
${response.status} ${response.statusText}
</span>`;
if (typeof data === 'object') {
document.getElementById('response').textContent =
JSON.stringify(data, null, 2);
} else {
document.getElementById('response').textContent = data;
}
} catch (error) {
document.getElementById('status').innerHTML =
'<span class="status error">Network Error</span>';
document.getElementById('response').textContent =
'Error: ' + error.message;
}
}
window.onload = function() {
const savedKey = localStorage.getItem('apiKey');
if (savedKey) {
document.getElementById('apikey').value = savedKey;
}
};
document.getElementById('apikey').addEventListener('change', function(e) {
localStorage.setItem('apiKey', e.target.value);
});
</script>
</body>
</html>