- 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>
89 lines
2.8 KiB
Java
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;
|
|
}
|
|
}
|