Skip to content

Handle non-root path requests #232

Description

@ComputerDaddyGuy

Hello,

For my use case, I would need java-httpbin to support handling requests on non-root paths, not only on the root path.

For example, for the /headers endpoint, we are currently forced to call http://127.0.0.1:8080/headers, whereas in my case I would need to call http://127.0.0.1:8080/some/other/path/headers (which returns 501 Not Implemented).

I thought of three possible options. Please let me know your thoughts, or if there is another option I may have missed.

Thank you!


Option 1: Custom HttpBinHandler

As mentioned in #15, I could indeed implement my own HttpBinHandler, but it would mostly be copy-and-paste work.

Since I would need to keep my implementation in sync with future changes in java-httpbin, this solution is neither ideal nor future-proof.


Option 2: Modify HttpBinHandler to support non-root paths

Modify HttpBinHandler so that it also handles non-root paths by default.

Not sure it is a valid approach as it seems to be a breaking change.

// HttpBinHandler
if (method.equals("GET") && uri.equals("/headers")) // Current implementation
if (method.equals("GET") && uri.endsWith("/headers")) // Proposed implementation: "endsWith" instead of "equals"

Option 3: Refactor HttpBinHandler to make it easier to extend/override

Instead of having a large if / else if / else block in a single method, perhaps a List<HttpBinRoute> could be introduced and iterated until a matching route is found.

This would make it easy to:

  • Extend existing routes to adjust matching logic or behavior
  • Add custom routes and behavior that are not provided by java-httpbin

It requires a bit more work, but it is also the most flexible approach. I would be glad to help 😊.

/** 
  * HttpBinHandler
  */

private List<HttpBinRoute> customRoutes = new ArrayList<>(); // mutable with some addCustomRoute(HttpBinRoute) method
private List<HttpBinRoute> defaultRoutes = /* default routes */;

private void handleHelper(Request baseRequest, HttpServletRequest request,
        HttpServletResponse servletResponse, InputStream is,
        OutputStream os) throws IOException {
    if(!handleRoutes(customRoutes, baseRequest, request, servletResponse, is, os)) { // Try first to handle request with custom routes...
        handleRoutes(defaultRoutes , baseRequest, request, servletResponse, is, os); // ... fallback to default routes otherwise
    }
}

private boolean handleRoutes(List<HttpBinRoute> routes, Request baseRequest, HttpServletRequest request,
        HttpServletResponse servletResponse, InputStream is,
        OutputStream os) throws IOException {
    // try
    for(var route : routes) {
        if(route.matches(request)) {
            route.handle(baseRequest, request, servletResponse, is, os);
            return true;
        }
    }
    // catch JSONException
    return false;
}

// ------------------------------------------------------------------------------

/** 
  * New interface
  */
public interface HttpBinRoute {

    boolean matches(Request request);

    void handle(Request baseRequest, HttpServletRequest request, 
            HttpServletResponse servletResponse, InputStream is,
            OutputStream os) throws IOException;
}

/** 
  * Default implementation from java-httpbin.
  * One implementation for each route handled by java-httpbin: HeadersRoute, GetRoute, PostRoute, IpRoute, etc.
  */
public class HeadersRoute implements HttpBinRoute {

    public boolean matches(Request request) {
        return request.getMethod().equals("GET") && request.getRequestURI().equals("/headers");
    }

    public void handle(...) throw IOException, JSONException {
        // default implementation from HttpBinHandler
    }
}

// ------------------------------------------------------------------------------

/**
  * Custom implementation that only overrides the "matches" method.
  */
public class MyCustomHeadersRoute extends HeadersRoute {

    @Override
    public boolean matches(Request request) {
        return request.getMethod().equals("GET") && request.getRequestURI().endsWith("/headers");
    }

}

var handler = new HttpBinHandler();
handler.addCustomRoute(new MyCustomHeadersRoute());
var httpBin = new HttpBin( uri, handler );
httpBin.start();

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions