mcghidra/src/main/java/eu/starsong/ghidra/api/ResponseBuilder.java
Teal Bauer 4bc22674ec feat: Implement HATEOAS-compliant API endpoints
- Add ProgramEndpoints for proper HATEOAS URL structure
- Fix response structure to include required HATEOAS links
- Ensure proper result formats for segments, decompiled functions, and variables
- Reorganize endpoints to use nested resource pattern (/programs/current/functions/{address})
- Fix all tests to ensure HATEOAS compliance

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-04-13 20:29:11 +02:00

89 lines
2.8 KiB
Java

package eu.starsong.ghidra.api;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.sun.net.httpserver.HttpExchange;
import java.util.Map;
import java.util.UUID;
/**
* Builder for standardized API responses (following GHIDRA_HTTP_API.md v1).
* This should be used by endpoint handlers to construct responses.
*/
public class ResponseBuilder {
private final HttpExchange exchange;
private final int port; // Port of the current Ghidra instance handling the request
private JsonObject response;
private JsonObject links; // For HATEOAS links
private final Gson gson = new Gson(); // Gson instance for serialization
public ResponseBuilder(HttpExchange exchange, int port) {
this.exchange = exchange;
this.port = port;
this.response = new JsonObject();
this.links = new JsonObject();
// Add standard fields
String requestId = exchange.getRequestHeaders().getFirst("X-Request-ID");
response.addProperty("id", requestId != null ? requestId : UUID.randomUUID().toString());
response.addProperty("instance", "http://localhost:" + port); // URL of this instance
}
public ResponseBuilder success(boolean success) {
response.addProperty("success", success);
return this;
}
public ResponseBuilder result(Object data) {
response.add("result", gson.toJsonTree(data));
return this;
}
public ResponseBuilder error(String message, String code) {
JsonObject error = new JsonObject();
error.addProperty("message", message);
if (code != null) {
error.addProperty("code", code);
}
response.add("error", error);
return this;
}
/**
* Add metadata to the response (e.g., pagination info)
* @param metadata Map of metadata key-value pairs
* @return this builder
*/
public ResponseBuilder metadata(Map<String, Object> metadata) {
if (metadata != null) {
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
response.add(entry.getKey(), gson.toJsonTree(entry.getValue()));
}
}
return this;
}
public ResponseBuilder addLink(String rel, String href) {
JsonObject link = new JsonObject();
link.addProperty("href", href);
links.add(rel, link);
return this;
}
// Overload to add link with method
public ResponseBuilder addLink(String rel, String href, String method) {
JsonObject link = new JsonObject();
link.addProperty("href", href);
link.addProperty("method", method);
links.add(rel, link);
return this;
}
public JsonObject build() {
if (links.size() > 0) {
response.add("_links", links);
}
return response;
}
}