-
-
Notifications
You must be signed in to change notification settings - Fork 0
HTTP
Samuel De Oliveira edited this page Jan 12, 2026
·
2 revisions
Make HTTP requests to external APIs with built-in JSON serialization, caching, and connection pooling.
The HTTP API provides a powerful HTTP client for making REST API calls:
- RESTful Methods — GET, POST, PUT, DELETE support
- JSON Serialization — Automatic JSON parsing with Jackson
- Connection Pooling — Reuse connections with ApiPool
- Response Caching — Optional caching for GET requests
- Custom Headers — Add authentication tokens and custom headers
- Health Checks — Built-in ping() method
- Timeout Control — Configure request timeouts
- Type Safety — Generic type support
- Getting Started
- ApiManager — HTTP Client
- ApiPool — Connection Pool
- HTTP Methods
- Response Handling
- Caching
- Authentication
- Advanced Usage
- Best Practices
- Complete Examples
import fr.dreamin.dreamapi.api.http.ApiManager;
import fr.dreamin.dreamapi.api.http.core.ApiPool;
public class MyPlugin extends DreamPlugin {
@Override
public void onDreamEnable() {
// Create and register API client
ApiManager api = ApiPool.register("myapi", new ApiManager.Builder()
.baseUrl("https://api.example.com")
.timeout(5000)
.build()
);
// Test connection
if (api.ping()) {
getLogger().info("API is online!");
}
}
@Override
public void onDreamDisable() {
// Close all connections
ApiPool.closeAll();
}
}ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.timeout(5000)
.build();ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("Authorization", "Bearer YOUR_TOKEN")
.header("User-Agent", "MyPlugin/1.0")
.timeout(10000)
.build();ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.enableCache(true)
.cacheTtl(60000) // Cache for 60 seconds
.build();ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com") // Required
.timeout(5000) // Request timeout (ms)
.header("Authorization", "Bearer token") // Custom header
.enableCache(true) // Enable response caching
.cacheTtl(30000) // Cache TTL (ms)
.mapper(customObjectMapper) // Custom Jackson mapper
.build();if (api.ping()) {
player.sendMessage(
Component.text("API is reachable", NamedTextColor.GREEN)
);
} else {
player.sendMessage(
Component.text("API is down", NamedTextColor.RED)
);
}The ApiPool manages multiple API clients globally.
// Register with instance
ApiManager api = ApiPool.register("github", new ApiManager.Builder()
.baseUrl("https://api.github.com")
.header("Accept", "application/vnd.github.v3+json")
.build()
);
// Register with supplier (lazy + health check)
ApiManager api = ApiPool.register("myapi", () ->
new ApiManager.Builder()
.baseUrl("https://api.example.com")
.build()
);// Get by label (throws if not found)
ApiManager api = ApiPool.get("github");
// Find by label (returns Optional)
Optional<ApiManager> optional = ApiPool.find("github");
if (optional.isPresent()) {
ApiManager api = optional.get();
}
// Check if exists
if (ApiPool.exists("github")) {
ApiManager api = ApiPool.get("github");
}// Get all registered APIs
Collection<ApiManager> all = ApiPool.all();
for (ApiManager api : all) {
getLogger().info("API: " + api.getBaseUrl());
}
// Unregister single API
ApiPool.unregister("github");
// Close all connections
ApiPool.closeAll();// Simple GET
User user = api.get("/users/123", User.class);
player.sendMessage(
Component.text("User: " + user.getName(), NamedTextColor.GREEN)
);import com.fasterxml.jackson.core.type.TypeReference;
// Get list of objects
List<User> users = api.getAll("/users", new TypeReference<List<User>>() {});
for (User user : users) {
getLogger().info("User: " + user.getName());
}// Create user
String json = "{\"name\":\"John\",\"email\":\"john@example.com\"}";
User newUser = api.post("/users", json, User.class);
player.sendMessage(
Component.text("Created user: " + newUser.getId(), NamedTextColor.GREEN)
);// Update user
String json = "{\"name\":\"John Doe\"}";
User updated = api.put("/users/123", json, User.class);
player.sendMessage(
Component.text("Updated user", NamedTextColor.GREEN)
);// Delete user
DeleteResponse response = api.delete("/users/123", DeleteResponse.class);
if (response.isSuccess()) {
player.sendMessage(
Component.text("User deleted", NamedTextColor.GREEN)
);
}// Simple model
public class User {
private int id;
private String name;
private String email;
// Getters and setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}try {
User user = api.get("/users/123", User.class);
player.sendMessage(
Component.text("User: " + user.getName(), NamedTextColor.GREEN)
);
} catch (ApiManager.ApiRequestException e) {
player.sendMessage(
Component.text("API Error: " + e.getMessage(), NamedTextColor.RED)
);
getLogger().severe("Status: " + e.getStatusCode());
} catch (Exception e) {
player.sendMessage(
Component.text("Request failed", NamedTextColor.RED)
);
e.printStackTrace();
}import org.bukkit.Bukkit;
public void fetchUserAsync(Player player, int userId) {
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
try {
User user = ApiPool.get("myapi").get("/users/" + userId, User.class);
// Return to main thread
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("User: " + user.getName(), NamedTextColor.GREEN)
);
});
} catch (Exception e) {
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("Failed to fetch user", NamedTextColor.RED)
);
});
}
});
}ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.enableCache(true)
.cacheTtl(60000) // Cache for 60 seconds
.build();// First request - fetches from API
User user1 = api.get("/users/123", User.class); // API call
// Second request within TTL - returns from cache
User user2 = api.get("/users/123", User.class); // From cache
// After TTL expires - fetches from API again
Thread.sleep(61000);
User user3 = api.get("/users/123", User.class); // API callNote: Only GET requests are cached.
ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
.build();ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("X-API-Key", "your-api-key-here")
.build();import java.util.Base64;
String credentials = "username:password";
String encoded = Base64.getEncoder().encodeToString(
credentials.getBytes(StandardCharsets.UTF_8)
);
ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("Authorization", "Basic " + encoded)
.build();public void makeAuthenticatedRequest(String token) {
ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("Authorization", "Bearer " + token)
.build();
try {
User user = api.get("/me", User.class);
getLogger().info("Authenticated as: " + user.getName());
} catch (Exception e) {
e.printStackTrace();
}
}public class MultiApiPlugin extends DreamPlugin {
@Override
public void onDreamEnable() {
// GitHub API
ApiPool.register("github", new ApiManager.Builder()
.baseUrl("https://api.github.com")
.header("Accept", "application/vnd.github.v3+json")
.build()
);
// Discord API
ApiPool.register("discord", new ApiManager.Builder()
.baseUrl("https://discord.com/api/v10")
.header("Authorization", "Bot YOUR_BOT_TOKEN")
.build()
);
// Custom API
ApiPool.register("custom", new ApiManager.Builder()
.baseUrl("https://myapi.example.com")
.header("X-API-Key", "secret")
.enableCache(true)
.cacheTtl(30000)
.build()
);
}
public void fetchFromMultipleApis() {
try {
// GitHub
var repo = ApiPool.get("github").get("/repos/owner/repo", GitHubRepo.class);
// Discord
var guild = ApiPool.get("discord").get("/guilds/123456789", DiscordGuild.class);
// Custom
var data = ApiPool.get("custom").get("/data", CustomData.class);
} catch (Exception e) {
e.printStackTrace();
}
}
}import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiManager api = new ApiManager.Builder()
.baseUrl("https://api.example.com")
.mapper(mapper)
.build();// Build URL with query params
String path = "/users?page=1&limit=10";
List<User> users = api.getAll(path, new TypeReference<List<User>>() {});
// Or use helper
String path = String.format("/users?page=%d&limit=%d", 1, 10);public void createUserWithDetails(String name, String email) {
String json = String.format(
"{\"name\":\"%s\",\"email\":\"%s\",\"role\":\"user\"}",
name, email
);
try {
User user = ApiPool.get("myapi").post("/users", json, User.class);
getLogger().info("Created user: " + user.getId());
} catch (ApiManager.ApiRequestException e) {
getLogger().severe("Failed to create user: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}-
Register on enable — Initialize APIs in
onDreamEnable() -
Close on disable — Call
ApiPool.closeAll()inonDreamDisable() - Use async — Make HTTP requests asynchronously
- Handle exceptions — Always catch exceptions
- Test with ping() — Check API health on startup
- Use caching — Enable for frequently accessed data
- Store tokens safely — Use configuration files
- Define response models — Create POJOs for type safety
- Don't block main thread — Use async for all HTTP requests
- Don't hardcode tokens — Use config files
- Don't ignore timeouts — Set appropriate timeout values
- Don't leak connections — Always close ApiManager
- Don't log sensitive data — Be careful with tokens in logs
- Don't retry forever — Implement retry limits
public class GitHubPlugin extends DreamPlugin {
private static final String API_LABEL = "github";
@Override
public void onDreamEnable() {
// Register GitHub API
ApiPool.register(API_LABEL, new ApiManager.Builder()
.baseUrl("https://api.github.com")
.header("Accept", "application/vnd.github.v3+json")
.timeout(10000)
.build()
);
// Test connection
if (ApiPool.get(API_LABEL).ping()) {
getLogger().info("GitHub API connected");
}
}
@Override
public void onDreamDisable() {
ApiPool.closeAll();
}
public void getRepository(Player player, String owner, String repo) {
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
try {
String path = String.format("/repos/%s/%s", owner, repo);
GitHubRepo repository = ApiPool.get(API_LABEL).get(path, GitHubRepo.class);
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("Repository: " + repository.getName(), NamedTextColor.GREEN)
);
player.sendMessage(
Component.text("Stars: " + repository.getStargazersCount(), NamedTextColor.GOLD)
);
player.sendMessage(
Component.text("Language: " + repository.getLanguage(), NamedTextColor.AQUA)
);
});
} catch (Exception e) {
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("Failed to fetch repository", NamedTextColor.RED)
);
});
}
});
}
}
// Response model
class GitHubRepo {
private String name;
private String description;
private int stargazersCount;
private String language;
// Getters
public String getName() { return name; }
public String getDescription() { return description; }
public int getStargazersCount() { return stargazersCount; }
public String getLanguage() { return language; }
}public class UserApiPlugin extends DreamPlugin {
private ApiManager api;
@Override
public void onDreamEnable() {
api = ApiPool.register("users", new ApiManager.Builder()
.baseUrl("https://api.example.com")
.header("Authorization", "Bearer YOUR_TOKEN")
.enableCache(true)
.cacheTtl(30000)
.build()
);
}
// CREATE
public void createUser(String name, String email) {
String json = String.format(
"{\"name\":\"%s\",\"email\":\"%s\"}",
name, email
);
try {
User user = api.post("/users", json, User.class);
getLogger().info("Created user: " + user.getId());
} catch (Exception e) {
getLogger().severe("Failed to create user: " + e.getMessage());
}
}
// READ
public User getUser(int id) {
try {
return api.get("/users/" + id, User.class);
} catch (Exception e) {
getLogger().severe("Failed to get user: " + e.getMessage());
return null;
}
}
// READ ALL
public List<User> getAllUsers() {
try {
return api.getAll("/users", new TypeReference<List<User>>() {});
} catch (Exception e) {
getLogger().severe("Failed to get users: " + e.getMessage());
return Collections.emptyList();
}
}
// UPDATE
public void updateUser(int id, String name) {
String json = String.format("{\"name\":\"%s\"}", name);
try {
User user = api.put("/users/" + id, json, User.class);
getLogger().info("Updated user: " + user.getName());
} catch (Exception e) {
getLogger().severe("Failed to update user: " + e.getMessage());
}
}
// DELETE
public void deleteUser(int id) {
try {
api.delete("/users/" + id, DeleteResponse.class);
getLogger().info("Deleted user: " + id);
} catch (Exception e) {
getLogger().severe("Failed to delete user: " + e.getMessage());
}
}
}
// Models
class User {
private int id;
private String name;
private String email;
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
class DeleteResponse {
private boolean success;
public boolean isSuccess() { return success; }
}public class WeatherPlugin extends DreamPlugin {
@Override
public void onDreamEnable() {
ApiPool.register("weather", new ApiManager.Builder()
.baseUrl("https://api.weatherapi.com/v1")
.header("key", "YOUR_API_KEY")
.enableCache(true)
.cacheTtl(300000) // Cache for 5 minutes
.build()
);
}
public void getWeather(Player player, String city) {
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
try {
String path = String.format("/current.json?q=%s", city);
WeatherData weather = ApiPool.get("weather").get(path, WeatherData.class);
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("Weather in " + city, NamedTextColor.GOLD)
);
player.sendMessage(
Component.text("Temperature: " + weather.getCurrent().getTempC() + "°C",
NamedTextColor.AQUA)
);
player.sendMessage(
Component.text("Condition: " + weather.getCurrent().getCondition().getText(),
NamedTextColor.GREEN)
);
});
} catch (Exception e) {
Bukkit.getScheduler().runTask(this, () -> {
player.sendMessage(
Component.text("Failed to fetch weather", NamedTextColor.RED)
);
});
}
});
}
}
class WeatherData {
private Current current;
public Current getCurrent() { return current; }
static class Current {
private double tempC;
private Condition condition;
public double getTempC() { return tempC; }
public Condition getCondition() { return condition; }
}
static class Condition {
private String text;
public String getText() { return text; }
}
}- 🔧 Configuration — Store API keys in config
- 📦 Services — Use dependency injection
- ⚡ Scheduler — Schedule periodic API calls
- 🗄️ Database — Store API responses