Setting HTTP response code?

Poster Content
nk4um User
Posts: 168
September 4, 2011 06:43

Hi!

Thank you all for your interesting answers! For information, I used Peter's solution of isolating the client login verification from the client resource representation.

Grégoire

Like · Post Reply
nk4um Moderator
Posts: 901
August 23, 2011 11:31

Incidentally - as far as I can read in this thread - this has absolutely nothing to do with verb translation (so worrying about Chris's HTTPAccessor is a red-herring). Its purely about clean separation of concerns/resource models.

Like · Post Reply
nk4um Moderator
Posts: 901
August 23, 2011 11:12A Resource Oriented Solution

So the last post was a hack and it is bad. The reason it is bad is that your service res:/clients/* is not separating out the resources that are required for the external HTTP service and those which are required to decide if a user has the right credentials.

These are two different things and what Tony and Chris were suggesting was that you think in terms of a resource set that is the valdiated user set. If I were modelling this I would call this...

active:validUser+id@...+password@...

Where the response would be a boolean true/false representation.

Then from your service which only wants to know if a user is valid (the one that started all the trouble) I would call...

req=context.createRequest("active:validUser")
req.addArgumentByValue("id", someid);
req.addArgumentByValue("password", somepwd);

This resource is now the validity of this user id:passwd combo.

But now in your res:/clients/* service implementation (the one you were mixing up and trying to overload before) all you do is make the same request for the same resource...

req=context.createRequest("active:validUser")
req.addArgumentByValue("id", someid);
req.addArgumentByValue("password", somepwd);
valid=context.issueRequest(req);

responseCode=null
if(valid)
{ responseCode=200
}
else
{ responseCode=401
}
context.sink("httpResponse:/code", responseCode)

The reason that Chris and Tony (and I) recommend this is that now you have a clean normalized resource set (active:validUser) - which you can use not only for HTTP requests but for any other service (which you clearly needed already).

You have also decoupled the rather arbitrary response codes of the HTTP domain from a simple true/false statement about the nature of validity of the user login. This could be used in a gatekeeper overlay or many other services.

Finally the benefit of this approach over a conventional object oriented internal REST framework is that it is completely stateless and thread safe and scaleable and was really no work at all.

P.

Like · Post Reply
nk4um User
Posts: 177
August 23, 2011 11:07

Hi Gregoire,

Ok. Now I understand your pain!

I'm not a 1060Research employee, so can't comment on what their focuses of the NetKernel team are (EDIT: it seems Peter and Tony have beaten me to a response!).

Thinking about it, you're right and it needs to be easier to create a HTTP REST service in NetKernel. It doesn't live in the internals/core of NetKernel though. I contributed HttpAccessorImpl to 1060 with the aim of making this easier, but it is still not obvious - there are potentially other architectural approaches that could be taken to make this HTTP/NetKernel verb translation easier (e.g. a HTTP aware mapper overlay). Maybe this could somehow be added to ncode in someway?

This probably should be a well documented sample so that a NetKernel degree isn't required in order to achieve this reasonably simple requirement which naturally looks right for NetKernel.

Best wishes,

Chris

Like · Post Reply
nk4um Administrator
Posts: 607
August 23, 2011 11:02

Hi Gregoire,

I think there is some truth in that document for sure! But I think there is exaggeration. I'm sorry you are feeling downhearted but I can't apologize for the way NetKernel is. There are many platforms out there that solve the much simpler task of just implementing REST services tied to HTTP.

NetKernel from the start has been about something much bigger and that inevitably has meant a steeper learning curve. We often have discussions about the tradeoffs of specific frameworks for specific jobs vs. general abstractions and the kinds of complexities that lead from each. I want to be clear that there are some rough edges with NetKernel, particularly in the different pathways of learning required within the documentation. However we are always working to improve those based on feedback and experiences we observe.

Let me enumerate a few of the reasons why NetKernel is not just a HTTP Rest framework and why it is unique in it's approach. An approach that takes learning but yields real benefits:

  1. the REST approach is taken deep into the software not just on the surface
  2. intrinsic caching throughout the software architecture
  3. abstraction for separating software architecture from code
  4. rapid development - prototype is the deliverable (once you know the approach)
  5. creates software that is very malleable to change
  6. very strong modularity with advanced features such as dynamic import that even OSGI can't match
  7. exposure of services across many transports not just HTTP but email, JMS, P2P etc
  8. libraries of functionality with much lower learning curve than APIs

I hope you do persevere but if these benefits don't interest you then maybe a more direct REST framework such as Restlets may appeal?

Cheers, Tony

Like · Post Reply
nk4um Moderator
Posts: 901
August 23, 2011 10:58

Hi Gregoire (Chris / Tony),

I think there's a degree of confusion going on here.

Firstly Gregoire if all you want is a "quick hack" then the following will work...

INKFRequest myRequestClient = context.createRequest("res:/clients/"+myId+":"+myPassword);
INKFResponseReadOnly myResponseClient = context.issueRequestForResponse(myRequestClient);
int myResponseCode = myResponseClient.getHeader("GREGOIRES_PASSWORD_STATUS_CODE");

Where you must make the implementation of the res:/clients/* service add a header with the code like this...

blah....
response.setHeader("GREGOIRES_PASSWORD_STATUS_CODE", code);

But for many reasons this is just horrible.

In the next post I'll explain what Tony and Chris are suggesting and why it would help you to think in terms of resources...

P.

Like · Post Reply
nk4um User
Posts: 168
August 23, 2011 10:35

Hi Chris,

Truth is that I'm quite downhearted. Assuming that this document is not a joke, I don't want to be harsh, but I feel like NetKernel's team should focus on what users do and make these things easy.

REST is about using HTTP extensively, including verbs and status codes, to access resources with various representations and keep clean/solid URIs. This seems to be a rather common use-case.

From a user point of view, knowing that NetKernel is a pure ROC microkernel is of little practical value, particularly if this implies that one needs to understand NetKernel's internals to make a simple REST server over HTTP. Most people won't go further.

I don't see why I should write this "ROC to HTTP" bridge. Is this related to the "verb translation pattern"?

As I said, English is not my native language and if this message sounds harsh, it was not intended to be.

Thanks, Gregoire

Like · Post Reply
nk4um User
Posts: 177
August 22, 2011 18:14

The intention of HttpAccessorImpl was to enable easy mapping between HTTP requests and ROC requests. I think Tony is correct and the being tightly coupled to HTTP is a bit of an anti-pattern here. The complexity added by separating the code is made up for in the improved architecture - it would strike me as more maintainable for two reasons:

  • The HTTP response code set by "A" will be set on the response of "C", unless you override it with a different value in "C". This could lead to subtle bugs in the future (e.g. difficult to track down).
  • The approach you describe is non-obvious.

Hope that helps,

Chris

Like · Post Reply
nk4um User
Posts: 168
August 22, 2011 15:31

Hi,

"A" and "C" are already bound to HTTP : they extend HttpAccessorImpl (because I need to detect GET, POST, PUT, etc). We had a discussion about the HTTP-to-ROC verb translation pattern and the conclusion was that extending HttpAccessorImpl was the easiest and cleanest solution.

In this context, adding a new layer ("B") that would just read the return code from A and sink it to httpResponse:/code would add complexity but would not be enough to not be tied to HTTP.

If there's no way to SOURCE httpResponse:/code from "C", then I'll try to add the HTTP code in script A's representation and read this code from "C".

Thanks, Grégoire

Like · Post Reply
nk4um Administrator
Posts: 607
August 22, 2011 10:39

Ok great!

Because your first service (let me call it service A) is tightly coupled to HTTP specifics you are going to have a problem. Basically the only way to access it is to request it over HTTP and not within the ROC address space. The best approach is to change service A to work without being coupled to HTTP and then write a thin adaption layer (service B) to expose it on HTTP. Then your additional service (service C) which want to reuse service A can use it directly.

This decoupling is a common pattern in ROC (bridge pattern). It allows you to create generic services and then target them at specific transports with a bridge. It is very closely analogous to the model-view pattern in OO.

There are a number of ways which you could implement a generic service A. One approach would be to return an XML document as the response. From this response service B could determine the correct HTTP response code.

Does this help? Tony

Like · Post Reply
nk4um User
Posts: 168
August 22, 2011 10:26

Yes.

Like · Post Reply
nk4um Administrator
Posts: 607
August 22, 2011 10:24

Just to check I understand: You have an existing service which you expose to the outside world over HTTP. This service has a path of the form /clients/id:password. This service sets the HTTP response code.

Now you want to reuse this service and make an internal request to it from another NetKernel service. And you wish to check the HTTP response code that was set inside that called service.

Is this correct? Tony

Like · Post Reply
nk4um User
Posts: 168
August 22, 2011 09:28

Hi Tony,

Well I have a service at /clients/id:password that can return the informations about a given user. If the password is correct, it returns 200, and if wrong, 401 (unauthorized).

I'm now in the process of writing a service which uses the "id:password" pairs, and to check if the credentials are ok, I'm doing an internal request to /clients/id:password. This is why I want to check if the returned code is 200 or 401.

Thanks, Grégoire

Like · Post Reply
nk4um Administrator
Posts: 607
August 22, 2011 09:20

Hi Gregoire,

maybe I'm missing something about what you are trying to achieve. NetKernel internal requests don't use HTTP and any of the semantics and specifics of HTTP don't apply. NetKernel responses don't have a response code like HTTP.

Please explain more about what you are trying to achieve.

Cheers, Tony

Like · Post Reply
nk4um User
Posts: 168
August 22, 2011 09:00

Hi Peter,

Actually, this is what I use :

INKFRequest myRequestClient = context.createRequest("res:/clients/"+myId+":"+myPassword);
INKFResponseReadOnly myResponseClient = context.issueRequestForResponse(myRequestClient);
int myResponseCode = myResponseClient.getHeader("HTTP_ACCESSOR_STATUS_CODE_METADATA");

and it returns the following error :

Metadata key not found
HTTP_ACCESSOR_STATUS_CODE_METADATA

If I use active:httpGet just like the example, i.e. :

INKFRequest myRequestClient = context.createRequest("active:httpGet");
myRequestClient.addArgumentByValue("url", "res:/clients/"+myId+":"+myPassword);
INKFResponseReadOnly myResponseClient = context.issueRequestForResponse(myRequestClient);
int myResponseCode = myResponseClient.getHeader("HTTP_ACCESSOR_STATUS_CODE_METADATA");

then the "res:" protocol is refused with :

org.apache.http.client.ClientProtocolException
URI does not specify a valid host name: pbv:url

Hence my question about the possibility to test the HTTP status code for internal requests.

Thanks, Gregoire

Like · Post Reply
nk4um Moderator
Posts: 901
August 22, 2011 08:06Response Header:

Hi Gregoire,

The HTTP response code is returned as metadata in the ROC response header HTTP_ACCESSOR_STATUS_CODE_METADATA

There's an example of its use in the docs...

http://docs.netkernel.org/book/view/book:client:http:book/doc:client:http:metadata

P.

Like · Post Reply
nk4um User
Posts: 168
August 21, 2011 20:57Reading httpResponse:/code for a subrequest?

Hi,

I'm trying to read the http status code from a subrequest in Groovy :

INKFRequest myRequestClient = context.createRequest("res:/clients/"+myId+":"+myPassword);
INKFResponseReadOnly myResponseClient = context.issueRequestForResponse(myRequestClient);
int myResponseCode = myResponseClient.?????;

Is this possible to read the http code when using res:?

Thanks, Gregoire

Like · Post Reply
nk4um User
Posts: 168
February 11, 2011 12:42
Ok,

Found it. It can be done by setting :

httpResponse:/code


with the context.sink method :

context.sink("httpResponse:/code", 204);


Sorry for the noise! I will update this thread if I encounter a problem.

Gregoire
Like · Post Reply
nk4um User
Posts: 168
February 11, 2011 12:36Setting HTTP response code?
Hi!

After studying this excellent DZone''s RESTful reference card sent by Peter in his newsletter, I realize that I should use HTTP status codes instead of my home-made response codes.

I searched in the documentation but I couldn''t find how to set HTTP status code header. I''d like to do this from Groovy scripts (because I use Groovy for all POST/PUT/DELETE requests, where status codes are compulsory), and if possible, from XQuery (used for GET requests).

Any help would be much appreciated!

Regards,
Gregoire
Like · Post Reply