Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternate HTTPObjects creation API #15

Open
ratamacue opened this issue May 11, 2015 · 3 comments
Open

Alternate HTTPObjects creation API #15

ratamacue opened this issue May 11, 2015 · 3 comments
Assignees

Comments

@ratamacue
Copy link
Contributor

Instead of extending HTTPObject, I would like to delegate to it. One way to achieve that is to create factory classes that generate HTTPObjects rather than classes that extend HTTPObject.

Instead of:

HttpObject speaker = new HttpObject("/speak"){
            @Override
            public Response get(Request req) {
                return OK(Html("Hello World"));
            }
        };

Something like:

HttpObject speaker = new HttpObject("/speak", Get(req->OK(Html("Hello World"))));

The Method Signature of the HttpObject constructor could take a vararg of handlers (with a check to ensure no duplicate verbs are used) such as

public HttpObject(String path, HttpVerbs... handlers)

Would anybody on this project object to me adding this interface to HTTPObjects?

@stupenrose
Copy link
Contributor

Sorry @ratamacue, I would have responded earlier but I just now noticed this. FWIW, @chrisalbright and @SeanShubin have recently shared similar thoughts to this. I think what people are feeling is the 'nouniness' of the api. To help respond/explain this aspect of the design, I've started work on a nouniness article.

To further elaborate, I think the core idea with the whole API in this regard is encapsulation of the behavior for a given URL. This is where the 'object' part of the 'httpobjects' name is unfortunate; I've always been concerned that it may give people the impression that object-orientation is the core concept here, when the real focus is on the encapsulation of URL + methods. This is my main point of departure from the more 'verby' APIs out there.

That said, there are times when the relationship between the URL and it's functionality is so generic that falling back to simple function composition (which still maintains the encapsulation) is appropriate, and it would be nice to make that easier.

Another aspect of the API worth considering is that it takes the "many resources, n verbs" part of the API seriously.

So, my main concerns are that:

  1. it should be focused on http resource composition (not 'routing')
  2. the user should get compile-time feedback when their composition is invalid wrt the # and types of methods

Option 1: compose()

Adding a 'compose' function that facilitates the style that I think you're shooting for. @chrisalbright, Matt Bague & I were playing with this the other day and came up with a scala signature that was something like this:

def compose(pathPattern:String, 
    get:(Request)=>Response = METHOD_NOT_ALLOWED,
    post:(Request)=>Response = METHOD_NOT_ALLOWED,
    put:(Request)=>Response = METHOD_NOT_ALLOWED,
    delete:(Request)=>Response = METHOD_NOT_ALLOWED,
    head:(Request)=>Response = METHOD_NOT_ALLOWED,
    options:(Request)=>Response = METHOD_NOT_ALLOWED):HttpObject

which you'd be able to use like so:

serve(compose("/message",
       get={r=> OK(Text(getMessage)}),
       put={r=> OK(Text(updateMessage(r))})

I'm envisioning a scala version of this, and perhaps a java8 version (in 2 separate modules, allowing the core API continue to support java6. FYI, there is already a scala module in the 1.x branch.

Option 2: Adding a 'verby' module.

This would live alongside 'core', etc, and provide an alternate universe of sorts for people who can't stomach the nouniness of the core API. But I'd much prefer the 'compose()' option above.

@stupenrose
Copy link
Contributor

anyhow, @ratamacue I guess my answer is that

  1. I'd rather not add it to HttpObject itself, rather, I'd prefer it take the form of a utility method, something like DSL.compose()
  2. I'd like it to produce compile time errors when one makes mistakes like adding 2 'GET' methods, etc.
  3. If it uses java 7+ features, that it be put in a separate java7/java8 utility module so as to retain java6 compatibility in the core API

That work for you?

@stupenrose
Copy link
Contributor

FYI, a while back I submitted a refinement of the scala 'compose' idea. This is slated to be released as part of the upcoming 1.x line.

https://github.com/cjdev/httpobjects/blob/1.x/scala-2.11/src/test/scala/org/httpobjects/scala/Demo.scala

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants