snake-query
Version:
Node.js SDK for Snake Query API
109 lines (91 loc) • 3.03 kB
JavaScript
const SchemaBuilder = require('./schema-builder');
class SnakeQuery {
constructor(apiKey) {
if (!apiKey) {
throw new Error('API key is required');
}
this.apiKey = apiKey;
this.baseUrl = 'https://app.snakequery.com/api/query';
}
async query(options) {
if (!options) {
throw new Error('Query options are required');
}
if (!options.query) {
throw new Error('Query is required');
}
if (!options.data && !options.fetchUrl) {
throw new Error('Either data or fetchUrl must be provided');
}
if (options.data && options.fetchUrl) {
throw new Error('Cannot provide both data and fetchUrl, choose one');
}
const requestBody = {
query: options.query,
...(options.data && { data: options.data }),
...(options.fetchUrl && { fetchUrl: options.fetchUrl }),
...(options.responseSchema && { responseSchema: options.responseSchema }),
...(options.debug !== undefined && { debug: options.debug })
};
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 60 * 1000 * 10);
const response = await fetch(this.baseUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify(requestBody),
signal: controller.signal,
});
clearTimeout(timeoutId);
const contentType = response.headers.get('content-type');
let result;
if (contentType && contentType.includes('application/json')) {
result = await response.json();
} else {
const textResult = await response.text();
result = {
message: `Server returned non-JSON response: ${response.statusText}`,
statusCode: response.status,
body: textResult.substring(0, 200) + (textResult.length > 200 ? '...' : '')
};
}
if (!response.ok) {
const error = new Error(result.message || `HTTP ${response.status}: ${response.statusText}`);
error.status = response.status;
error.response = result;
throw error;
}
if(result?.code !== 200) {
throw new Error(result)
}
return result?.data;
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request timeout: Snake Query API took too long to respond (10 minute limit)');
}
if (error.name === 'TypeError' && error.message.includes('fetch')) {
throw new Error('Network error: Unable to connect to Snake Query API');
}
throw error;
}
}
async queryWithData(query, data, options = {}) {
return this.query({
query,
data,
...options
});
}
async queryWithUrl(query, fetchUrl, options = {}) {
return this.query({
query,
fetchUrl,
...options
});
}
}
SnakeQuery.SchemaBuilder = SchemaBuilder;
module.exports = SnakeQuery;