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

Cormo.Web: Injecting responses #10

Open
hendryluk opened this issue Feb 9, 2015 · 4 comments
Open

Cormo.Web: Injecting responses #10

hendryluk opened this issue Feb 9, 2015 · 4 comments

Comments

@hendryluk
Copy link
Owner

Currently this is how you set response details (e.g. headers) with Cormo (or rather, WebApi):

[RestController]
public class MyController
{
    [Route, HttpGet]
    public HttpResponseMessage DoSomething()
    {
        /* ... */
        var response = Response.Ok(something);
        response.Headers.LastModified = content.LastModified;
        return response;
    }
}

That's the same way in JBoss.
But additionally, according to the CDI spec (or rather, JBoss Seam), there's an alternative way may be better for flattening your code, which is by injecting your HttpResponseMessage to components. The benefit being that setting headers can be done by any component, no longer necessarily only by your controller (or UI layer in general).
Ref: http://docs.jboss.org/seam/3/latest/reference/en-US/html_single/#injectablerefs.http_servlet_reponse
E.g.

public class MyShoppingCart
{
   [Inject] HttpResponseMessage _response;
   public void DoSomething()
   {
       /* ... */
       response.Headers.LastModified = items.LastModified;
   }
}

This will add the header to the response that's eventually returned by web-api, even though the controller code is totally oblivious to it:

[RestController]
public class MyController
{
    [Route, HttpGet]
    public string DoSomething()
    {
        /* ... */
        _cart.DoSomething();
        return something;
    }
}

This helps reducing vertical layering in your application and simplifies some code by removing some unnecessary patterns.
PS: I'll leave it to you to decide whether that's a "good practice" to mix http concerns into your components, but some components are inherently web-coupled, such as identities, security (e.g. anti-csrf), captcha, and web-analytics functionalities, which are all commonly designed as components/interceptors/decorators. CDI provides a decoupled way to wire those up without introducing noise in your controller.

@hendryluk hendryluk changed the title Injecting responses Cormo.Web: Injecting responses Feb 9, 2015
@jimmyp
Copy link

jimmyp commented Feb 9, 2015

Just this morning I was wrestling with how to return a NotFound response code when I didn't find an entity inside a domain service... I'm not sure I like the mixing of concerns, but I def see the value.

@hendryluk
Copy link
Owner Author

Ah i see. Yea there are 4 ways you could do that in Cormo (pulled straight out of jax-rs playbook). Not very well documented (sorry about that).

Option 1

[Route, HttpGet, HttpStatusCode(HttpStatusCode.NotFound)]
public object Something()
{
}

That's probably not very appropriate for not-found, but is certainly useful for redirects, ok, accepted, etc.

Option 2

[Route, HttpGet]
public HttpMessageResponse Something()
{
    return Response.NotFound();
}

Which is more appropriate for not-found case.

Option 3

(Note that this, exception-handling, is currently not yet implemented in cormo, but it's part of CDI spec).
Issue: #12

[Route, HttpGet]
public object Something()
{
    throw MyNotFoundException();
}

public void OnNotFoundException(
     [HandlesException] MyNotFoundException, 
     HttpResponseMessage response)
{
   response.StatusCode = HttpStatusCode.NotFound;
}

Which could be shortened into:

[HttpStatusCode(HttpStatusCode.NotFound)]
public void OnNotFoundException([HandlesException] MyNotFoundException)
{
}

Then you can throw that exception from anywhere within your application.
Note that this is part of standard core CDI spec, not web specific. So you declare this exception-handling methods on any components for any purpose, not just for web and status-code stuff.

Option 4

Again, not yet implemented. Similar to option#3, but instead of exception-handling method, you got:

[HttpStatusCode(HttpStatusCode.NotFound)]
public class MyNotFoundException: Exception
{
}

And lastly

Of course the good old web-api way:

public class MyController: ApiController
{
   [Route, HttpGet]
   public IHttpActionResult Something()
   {
      return NotFound();
   }
}

@jimmyp
Copy link

jimmyp commented Feb 9, 2015

I was thinking of implementing something like option 3 myself. Nice.

@hendryluk
Copy link
Owner Author

I've created an issue for implementing CDI's exception-handling: #12

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

No branches or pull requests

2 participants