Documentation
HTTP Fetch
Make HTTP requests to external APIs and web services with built-in error handling and JSON parsing.
The "fetch" API
The fetch function allows you to make HTTP requests to external APIs and web services directly from your scripts.
Use it to integrate with REST APIs, retrieve data from web services, send webhooks, or communicate with external systems.
⚠️ Important: The fetch function is synchronous and will block execution until the response is received.
Always run fetch calls asynchronously using Scheduler.runAsync() to avoid freezing the server.
Making HTTP Requests
Basic GET request with fetch(url, options? )
Makes an HTTP request to the specified URL and returns a Response object.
Parameters:
url- The URL to send the request to (e.g.,"https://api.example.com/data")options(optional) - Configuration object containing:method- HTTP method (GET,POST,PUT,DELETE,PATCH, etc.). Defaults toGETheaders- Object containing request headers as key-value pairspostBody- Body content to send withPOST,PUT, orPATCHrequests
Scheduler.runAsync(() => { const response = fetch("https://gateway.openaudiomc.net/"); if (response.isSuccessful()) { log("Status code: " + response. getStatusCode()); log("Response body: " + response.asString()); // Parse the JSON response const parsedResponse = response.asObject(); log("MOTD: " + parsedResponse.motd); } else { log("Request failed with status: " + response.getStatusCode()); } });
Processing Responses
The Response object provides several methods to access and process response data:
Get response as string with response.asString()
Returns the raw response body as a string.
const response = fetch("https://api.example.com/data"); const bodyText = response.asString(); log("Raw response: " + bodyText);
Parse JSON response with response.asObject()
Parses the response body as JSON and returns a JavaScript object.
const response = fetch("https://api.example.com/user/123"); if (response.isSuccessful()) { const user = response.asObject(); log("User ID: " + user.id); log("Username: " + user.name); log("Email: " + user. email); }
Get HTTP status code with response.getStatusCode()
Returns the HTTP status code of the response.
const response = fetch("https://api.example.com/data"); const statusCode = response.getStatusCode(); log("Status code: " + statusCode); // 200 = OK, 404 = Not Found, 500 = Server Error, etc.
Check response status with response.isSuccessful() and response.isFailed()
Convenient methods to check if the request succeeded or failed.
const response = fetch("https://api.example.com/data"); if (response.isSuccessful()) { // Status code is between 200-399 log("Request succeeded!"); const data = response.asObject(); } else if (response.isFailed()) { // Status code is >= 400 or < 0 error("Request failed: " + response. getStatusCode()); }
Working with Headers
Adding custom headers
Headers are useful for authentication, content type specification, and API key authentication.
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/protected-resource", { headers: { "Authorization": "Bearer " + apiToken, "Content-Type": "application/json", "Accept": "application/json", "User-Agent": "PixelScript/1.0" } }); if (response.isSuccessful()) { const data = response.asObject(); log("Protected data: " + data.secretInfo); } });
Sending Data with POST Requests
POST request with JSON body
Use POST requests to send data to a server, such as creating resources or submitting forms.
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/users", { method: "POST", headers: { "Content-Type": "application/json" }, postBody: JSON.stringify({ name: "John Doe", email: "john@example.com", age: 30 }) }); if (response.isSuccessful()) { const createdUser = response.asObject(); log("Created user with ID: " + createdUser. id); } else { error("Failed to create user: " + response.asString()); } });
Using Different HTTP Methods
PUT request to update a resource
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/users/123", { method: "PUT", headers: { "Content-Type": "application/json" }, postBody: JSON. stringify({ name: "John Doe Updated", email: "john.updated@example.com" }) }); if (response.isSuccessful()) { log("User updated successfully"); } });
PATCH request for partial updates
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/users/123", { method: "PATCH", headers: { "Content-Type": "application/json" }, postBody: JSON. stringify({ email: "newemail@example.com" }) }); log("Partial update status: " + response.getStatusCode()); });
DELETE request to remove a resource
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/users/123", { method: "DELETE" }); if (response. isSuccessful()) { log("User deleted successfully"); } else { log("Failed to delete user: " + response.getStatusCode()); } });
Error Handling
Comprehensive error handling
Always check response status and handle errors appropriately.
Scheduler.runAsync(() => { try { const response = fetch("https://api.example.com/data"); if (response.isFailed()) { // Handle specific error cases const statusCode = response.getStatusCode(); if (statusCode === 404) { log("Resource not found"); } else if (statusCode === 401 || statusCode === 403) { log("Authentication or permission error"); } else if (statusCode === 429) { log("Rate limit exceeded - try again later"); } else if (statusCode >= 500) { log("Server error - the API may be down"); } else { log("Request failed with status: " + statusCode); log("Error message: " + response.asString()); } } else { // Process successful response const data = response.asObject(); log("Data received successfully"); } } catch (e) { // Catch unexpected errors (network issues, JSON parsing, etc.) error("Exception during fetch operation: " + e. message); } });
Practical Examples
Webhook notification system
function sendDiscordWebhook(webhookUrl, message) { Scheduler.runAsync(() => { const response = fetch(webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, postBody: JSON.stringify({ content: message, username: "PixelScript Bot" }) }); if (response.isSuccessful()) { log("Webhook sent successfully"); } else { error("Failed to send webhook: " + response. getStatusCode()); } }); } // Usage registerListener($. PlayerJoinEvent, (event) => { const player = event.getPlayer(); sendDiscordWebhook( "https://discord.com/api/webhooks/.. .", `${player.getName()} joined the server! ` ); });
Player UUID lookup
function lookupPlayerUUID(username, callback) { Scheduler.runAsync(() => { const response = fetch(`https://api.mojang.com/users/profiles/minecraft/${username}`); if (response.isSuccessful()) { const data = response.asObject(); Scheduler.runSync(() => { callback(data.id, data.name); }); } else { Scheduler.runSync(() => { callback(null, null); }); } }); } // Usage lookupPlayerUUID("Notch", (uuid, name) => { if (uuid) { log(`UUID for ${name}: ${uuid}`); } else { log("Player not found"); } });
API integration with authentication
class ExternalAPI { constructor(baseUrl, apiKey) { this.baseUrl = baseUrl; this.apiKey = apiKey; } get(endpoint, callback) { Scheduler.runAsync(() => { const response = fetch(`${this.baseUrl}${endpoint}`, { headers: { "Authorization": `Bearer ${this.apiKey}`, "Accept": "application/json" } }); if (response.isSuccessful()) { Scheduler.runSync(() => { callback(response.asObject(), null); }); } else { Scheduler.runSync(() => { callback(null, `Error ${response.getStatusCode()}: ${response.asString()}`); }); } }); } post(endpoint, data, callback) { Scheduler. runAsync(() => { const response = fetch(`${this.baseUrl}${endpoint}`, { method: "POST", headers: { "Authorization": `Bearer ${this.apiKey}`, "Content-Type": "application/json" }, postBody: JSON.stringify(data) }); if (response. isSuccessful()) { Scheduler.runSync(() => { callback(response.asObject(), null); }); } else { Scheduler.runSync(() => { callback(null, `Error ${response.getStatusCode()}: ${response.asString()}`); }); } }); } } // Usage const api = new ExternalAPI("https://api.example.com", "your-api-key"); api.get("/users/123", (data, error) => { if (error) { error("API error: " + error); } else { log("User data: " + data. name); } });
Server status checker
function checkServerStatus(serverUrl, callback) { Scheduler.runAsync(() => { try { const startTime = Date.now(); const response = fetch(serverUrl); const endTime = Date.now(); const pingTime = endTime - startTime; Scheduler.runSync(() => { callback({ online: response.isSuccessful(), statusCode: response.getStatusCode(), pingTime: pingTime }); }); } catch (e) { Scheduler.runSync(() => { callback({ online: false, statusCode: -1, pingTime: -1, error: e.message }); }); } }); } // Usage checkServerStatus("https://api.example.com/health", (status) => { if (status. online) { log(`Server is online (${status.pingTime}ms)`); } else { error("Server is offline"); } });
Batch data fetching
function fetchMultipleEndpoints(urls, callback) { const results = []; let completed = 0; urls.forEach((url, index) => { Scheduler.runAsync(() => { const response = fetch(url); results[index] = { url: url, success: response.isSuccessful(), data: response.isSuccessful() ? response.asObject() : null, statusCode: response.getStatusCode() }; completed++; if (completed === urls.length) { Scheduler.runSync(() => { callback(results); }); } }); }); } // Usage fetchMultipleEndpoints([ "https://api.example.com/users", "https://api.example.com/posts", "https://api.example.com/comments" ], (results) => { results.forEach(result => { log(`${result.url}: ${result.success ? "OK" : "FAILED"}`); }); });
HTTP Status Codes Reference
Common HTTP status codes you may encounter:
Success (2xx)
200- OK (request succeeded)201- Created (resource created successfully)204- No Content (success with no response body)
Client Errors (4xx)
400- Bad Request (invalid request format)401- Unauthorized (authentication required)403- Forbidden (insufficient permissions)404- Not Found (resource doesn't exist)429- Too Many Requests (rate limit exceeded)
Server Errors (5xx)
500- Internal Server Error (server-side error)502- Bad Gateway (upstream server error)503- Service Unavailable (server temporarily down)
Best Practices
✅ DO:
- Always run
fetchcalls insideScheduler.runAsync()to avoid blocking the server - Check response status with
isSuccessful()orisFailed()before processing - Wrap
asObject()calls in try-catch blocks to handle JSON parsing errors - Store API keys and tokens securely (never hardcode sensitive credentials)
- Implement proper error handling for network failures
- Use appropriate HTTP methods (
GETfor retrieval,POSTfor creation, etc.) - Set correct
Content-Typeheaders when sending data - Implement rate limiting when making frequent API calls
❌ DON'T:
- Call
fetchon the main thread (will freeze the server) - Ignore response status codes
- Make excessive requests in tight loops
- Hardcode sensitive credentials in your scripts
- Assume the response will always be valid JSON
- Make fetch calls in frequently executed code (like every tick)
- Forget to handle timeout scenarios (30-second timeout limit)
Timeout Behavior
The fetch function has built-in timeout protection:
- Connection timeout: 30 seconds
- Read timeout: 30 seconds
If a request takes longer than 30 seconds, it will fail automatically. Always handle timeout scenarios gracefully:
Scheduler.runAsync(() => { const response = fetch("https://slow-api.example.com/data"); if (response.isFailed()) { if (response.getStatusCode() < 0) { error("Request timed out or network error"); } else { error("Request failed with status: " + response.getStatusCode()); } } });
Thread Safety
When using fetch with async/sync patterns, remember:
// ✅ CORRECT: Fetch async, interact with Bukkit API sync Scheduler.runAsync(() => { const response = fetch("https://api.example.com/data"); const data = response.asObject(); // Switch to sync thread to interact with players Scheduler.runSync(() => { Bukkit.broadcastMessage("Data loaded: " + data.message); }); }); // ❌ WRONG: Calling Bukkit API from async thread Scheduler.runAsync(() => { const response = fetch("https://api.example.com/data"); Bukkit.broadcastMessage("Done! "); // ❌ This will cause errors! });
JSON Handling
When working with JSON responses, use proper error handling:
Scheduler.runAsync(() => { const response = fetch("https://api.example.com/data"); if (response.isSuccessful()) { try { const data = response.asObject(); log("Parsed data successfully"); } catch (e) { error("Failed to parse JSON: " + e.message); log("Raw response: " + response.asString()); } } });
Execute SQL queries and manage database operations with automatic connection pooling and error handling.
Log messages, warnings, and errors to the server console for debugging and monitoring.