Details

    • Type: New Feature New Feature
    • Status: Patch Available
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: framework
    • Labels:
      None

      Description

      Implement a REST servlet that will map REST requests to OFBiz services. Details are in the comments.

      here is the discussion which took place on the dev ML

      1. RestXmlRepresentation.xml
        22 kB
        Adrian Crum
      2. RestExampleSchema.xsd
        3 kB
        Adrian Crum
      3. rest-conf.xml
        4 kB
        Adrian Crum

        Activity

        Hide
        Ean Schuessler added a comment -

        Great stuff. What would you think about supporting cookie and session values as well?
        ie. <service-param name="sessionId" value="${_SESSION.sessionId}"/>

        It would also be useful if services could update session and cookie values.

        We will play with this code.

        Show
        Ean Schuessler added a comment - Great stuff. What would you think about supporting cookie and session values as well? ie. <service-param name="sessionId" value="${_SESSION.sessionId}"/> It would also be useful if services could update session and cookie values. We will play with this code.
        Hide
        Adrian Crum added a comment -

        No, <response-hyperlink>.

        Show
        Adrian Crum added a comment - No, <response-hyperlink>.
        Hide
        Jacques Le Roux added a comment -

        <options> is the way HATEOAS will be implemented?

        Show
        Jacques Le Roux added a comment - <options> is the way HATEOAS will be implemented?
        Hide
        Adrian Crum added a comment -

        Updated rest-conf.xml file - based on Scott's suggestion.

        Show
        Adrian Crum added a comment - Updated rest-conf.xml file - based on Scott's suggestion.
        Hide
        Adrian Crum added a comment -

        Thank you for the review Scott!

        I agree #1 would be nice to have, but I was trying to keep the initial implementation simple.

        I like the XML structure you suggested - I will update the file and create a schema.

        Show
        Adrian Crum added a comment - Thank you for the review Scott! I agree #1 would be nice to have, but I was trying to keep the initial implementation simple. I like the XML structure you suggested - I will update the file and create a schema.
        Hide
        Scott Gray added a comment -

        I've only looked at rest-conf.xml at this stage but the following issues come to mind:
        1. No support for sub-resources e.g. GET: /parties/10000/contactmechs/ While this could also be possible using contactmechs?partyId=10000, I don't think we should restrict APIs to a non-hierarchical structure.
        2. I think it might be better to structure the document by resource with child elements for methods e.g.

        <resource name="example">
          <post>
            <security https="true" auth="true"/>
            <invoke-service name="createExample">
            <!--
              The servlet will convert trailing path elements into a List, so they can be queried by code.
            -->
              <service-param name="exampleId" value="${pathElements[0]}"/>
            </invoke-service>
            <response-hyperlink resource="exampleItem"/>
            <response-hyperlink url="http://www.mydomain.com"/>
          </post>
          <!-- Updates (or creates) an Example -->
          <put>
            <security https="true" auth="true"/>
            <invoke-service name="updateExample">
              <service-param name="exampleId" value="${pathElements[0]}"/>
            </invoke-service>
            <response-hyperlink resource="exampleItem"/>
          </put>
        </resource>
        

        3. I think we're also missing the distinction between collection and instance methods whereby GET: /party/ and GET:/party/10000 access different services and return different results.

        That's all that comes to mind right now.

        Show
        Scott Gray added a comment - I've only looked at rest-conf.xml at this stage but the following issues come to mind: 1. No support for sub-resources e.g. GET: /parties/10000/contactmechs/ While this could also be possible using contactmechs?partyId=10000, I don't think we should restrict APIs to a non-hierarchical structure. 2. I think it might be better to structure the document by resource with child elements for methods e.g. <resource name= "example" > <post> <security https= "true" auth= "true" /> <invoke-service name= "createExample" > <!-- The servlet will convert trailing path elements into a List, so they can be queried by code. --> <service-param name= "exampleId" value= "${pathElements[0]}" /> </invoke-service> <response-hyperlink resource= "exampleItem" /> <response-hyperlink url= "http://www.mydomain.com" /> </post> <!-- Updates (or creates) an Example --> <put> <security https= "true" auth= "true" /> <invoke-service name= "updateExample" > <service-param name= "exampleId" value= "${pathElements[0]}" /> </invoke-service> <response-hyperlink resource= "exampleItem" /> </put> </resource> 3. I think we're also missing the distinction between collection and instance methods whereby GET: /party/ and GET:/party/10000 access different services and return different results. That's all that comes to mind right now.
        Hide
        Jacques Le Roux added a comment - - edited

        Not directly related and not even to OFBiz, but for those interested by this issue here is an article which pertains to REST

        Show
        Jacques Le Roux added a comment - - edited Not directly related and not even to OFBiz, but for those interested by this issue here is an article which pertains to REST
        Hide
        Jacques Le Roux added a comment -

        Also Sascha tweeted this interesting article for load testing rest apps http://www.codeaffine.com/2011/11/28/stressload-testing-of-asynchronous-httprest-services-with-jmeter/

        Show
        Jacques Le Roux added a comment - Also Sascha tweeted this interesting article for load testing rest apps http://www.codeaffine.com/2011/11/28/stressload-testing-of-asynchronous-httprest-services-with-jmeter/
        Hide
        Jacques Le Roux added a comment -

        Hi,

        Some weeks ago, I read this article http://www.javacodegeeks.com/2011/10/java-restful-api-integration-testing.html. Maybe it can help integration in OFBiz.
        Googling for such today I found also http://code.google.com/p/rest-client/. Of course there are alot of other interesting results when Googling for "restful testing"

        My 2 cts

        Show
        Jacques Le Roux added a comment - Hi, Some weeks ago, I read this article http://www.javacodegeeks.com/2011/10/java-restful-api-integration-testing.html . Maybe it can help integration in OFBiz. Googling for such today I found also http://code.google.com/p/rest-client/ . Of course there are alot of other interesting results when Googling for "restful testing" My 2 cts
        Hide
        Adrian Crum added a comment -

        Raj,

        I understand what you are saying, but the OFBiz service result does not provide enough information to affect the HTTP response headers. For example, if a user was not authorized to create a resource, then an HTTP status code of 403 should be returned. The problem is, OFBiz services do not categorize results that way - the results are either "success" or "error" - so there is no way for the servlet to map service responses to HTTP status codes. We could introduce a new service return type - like "not-authorized" or something similar, but that would involve rewriting all of the OFBiz services. There is no one-to-one mapping of OFBiz service results to HTTP response codes.

        As far as web client development is concerned, OFBiz REST client skeleton code could be provided to make development easier. There is nothing in the code snippet you provided that would prohibit a developer from connecting the Oracle Jersey client API to an OFBiz REST client API:

        
        OFBizRestClientRepresentation orcr = new OFBizRestClientRepresentation("xml");
        WebResource webResource = client.resource("https://localhost:8443/example/services/example");
        ClientResponse response = webResource.accept(orcr.getContentType()).get(ClientResponse.class);
        orcr.setResponse(response);
        if (orcr.success()) {
          // Process response
        } else {
          // Process error
        }
        
        
        Show
        Adrian Crum added a comment - Raj, I understand what you are saying, but the OFBiz service result does not provide enough information to affect the HTTP response headers. For example, if a user was not authorized to create a resource, then an HTTP status code of 403 should be returned. The problem is, OFBiz services do not categorize results that way - the results are either "success" or "error" - so there is no way for the servlet to map service responses to HTTP status codes. We could introduce a new service return type - like "not-authorized" or something similar, but that would involve rewriting all of the OFBiz services. There is no one-to-one mapping of OFBiz service results to HTTP response codes. As far as web client development is concerned, OFBiz REST client skeleton code could be provided to make development easier. There is nothing in the code snippet you provided that would prohibit a developer from connecting the Oracle Jersey client API to an OFBiz REST client API: OFBizRestClientRepresentation orcr = new OFBizRestClientRepresentation( "xml" ); WebResource webResource = client.resource( "https: //localhost:8443/example/services/example" ); ClientResponse response = webResource.accept(orcr.getContentType()).get(ClientResponse.class); orcr.setResponse(response); if (orcr.success()) { // Process response } else { // Process error }
        Hide
        Raj Saini added a comment -

        Adrian,

        Thanks for the clarification.

        There are RESTful client APIs in Java and other framework and developers may want to take advantage of these APIs. These client API follow the RESTful standard and they may depend on the HTTP headers and statuses. If we plan to use the XML based packaging and error handing, it will become the responsibility of the developer to handle all standard application errors at application level instead of delegating it to application. Below is a code snippet consuming RESTful services using Oracle Jersey client API. Client API is trying to get the response status and I guess it is only possible if response is a standard.

        WebResource webResource = client.resource("http://example.com/base");
        ClientResponse response = webResource.accept("text/plain").get(ClientResponse.class);
        int status = response.getStatus();
        String textEntity = response.getEntity(String.class);

        Show
        Raj Saini added a comment - Adrian, Thanks for the clarification. There are RESTful client APIs in Java and other framework and developers may want to take advantage of these APIs. These client API follow the RESTful standard and they may depend on the HTTP headers and statuses. If we plan to use the XML based packaging and error handing, it will become the responsibility of the developer to handle all standard application errors at application level instead of delegating it to application. Below is a code snippet consuming RESTful services using Oracle Jersey client API. Client API is trying to get the response status and I guess it is only possible if response is a standard. WebResource webResource = client.resource("http://example.com/base"); ClientResponse response = webResource.accept("text/plain").get(ClientResponse.class); int status = response.getStatus(); String textEntity = response.getEntity(String.class);
        Hide
        Adrian Crum added a comment -

        Raj,

        I apologize if the design description was not clear about HTTP status codes. Yes, of course HTTP status codes will be returned (since REST is nothing more than HTTP 1.1).

        What I tried to describe is the HTTP status code behavior when an OFBiz service returns an error: The service error will not affect the HTTP status code. Instead, a 200 HTTP status will be returned and the response body will contain the result of the service call - which describes the error returned by the service.

        The reason why OFBiz service errors are handled this way should be obvious from a web client perspective. If an OFBiz service returned an error and that error resulted in an HTTP error status being returned, then how would a web client (or developer) know what the service error was?

        Show
        Adrian Crum added a comment - Raj, I apologize if the design description was not clear about HTTP status codes. Yes, of course HTTP status codes will be returned (since REST is nothing more than HTTP 1.1). What I tried to describe is the HTTP status code behavior when an OFBiz service returns an error: The service error will not affect the HTTP status code. Instead, a 200 HTTP status will be returned and the response body will contain the result of the service call - which describes the error returned by the service. The reason why OFBiz service errors are handled this way should be obvious from a web client perspective. If an OFBiz service returned an error and that error resulted in an HTTP error status being returned, then how would a web client (or developer) know what the service error was?
        Hide
        Raj Saini added a comment -

        I am not the expert but one of my quick observation is RESTful responses should return HTTP status. HTTP response should be packaged as standard HTTP headers including status codes. http://restpatterns.org/HTTP_Status_Codes have lists of RESTful codes.

        Show
        Raj Saini added a comment - I am not the expert but one of my quick observation is RESTful responses should return HTTP status. HTTP response should be packaged as standard HTTP headers including status codes. http://restpatterns.org/HTTP_Status_Codes have lists of RESTful codes.
        Hide
        Adrian Crum added a comment -

        Updated all files, removed patch file.

        Show
        Adrian Crum added a comment - Updated all files, removed patch file.
        Hide
        Adrian Crum added a comment - - edited

        RestExample.xsd contains some schema examples. The schemas a re pretty basic - just enough to ensure the correct structure. They do not validate service parameters. That was a design decision to keep things flexible. To aid in development, the OPTIONS method could return a set of schemas that include XML templates (inside comments) that can be used to create the XML payloads.

        Show
        Adrian Crum added a comment - - edited RestExample.xsd contains some schema examples. The schemas a re pretty basic - just enough to ensure the correct structure. They do not validate service parameters. That was a design decision to keep things flexible. To aid in development, the OPTIONS method could return a set of schemas that include XML templates (inside comments) that can be used to create the XML payloads.
        Hide
        Adrian Crum added a comment - - edited

        A clear distinction needs to be made between HTTP status and service status. OFBiz service results will not be used to modify the HTTP response status. The service results are contained within the response body - so there is no need to manipulate the HTTP response status. If the request is sent to a valid URL, and if the service was invoked successfully, then the HTTP response status will be 200 (OK). The HTTP response status will be used as intended - to indicate an invalid URL (404), user is not authenticated (401), an exception was thrown while processing the request (500), etc. If a service returns an error, then the HTTP response status will be 200 (OK) and the response body will contain the service results - which will describe the error.

        Show
        Adrian Crum added a comment - - edited A clear distinction needs to be made between HTTP status and service status. OFBiz service results will not be used to modify the HTTP response status. The service results are contained within the response body - so there is no need to manipulate the HTTP response status. If the request is sent to a valid URL, and if the service was invoked successfully, then the HTTP response status will be 200 (OK). The HTTP response status will be used as intended - to indicate an invalid URL (404), user is not authenticated (401), an exception was thrown while processing the request (500), etc. If a service returns an error, then the HTTP response status will be 200 (OK) and the response body will contain the service results - which will describe the error.
        Hide
        Adrian Crum added a comment - - edited

        A nice feature to have would be the ability to support dynamic XML stylesheets so that REST XML clients can validate request/response bodies. The body XML would contain the stylesheet reference URL, and the servlet would create a stylesheet based on the REST configuration file/service definition.

        Example XML request payload:

        <post xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:noNamespaceSchemaLocation="http://localhost/webtools/entities/orderheaders/post.xsd">
        ...
        </post>
        
        Show
        Adrian Crum added a comment - - edited A nice feature to have would be the ability to support dynamic XML stylesheets so that REST XML clients can validate request/response bodies. The body XML would contain the stylesheet reference URL, and the servlet would create a stylesheet based on the REST configuration file/service definition. Example XML request payload: <post xmlns:xsi= "http: //www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation= "http: //localhost/webtools/entities/orderheaders/post.xsd" > ... </post>
        Hide
        Adrian Crum added a comment -

        The HTTP command OPTIONS should return information about the service in the response body - in the requested format.

        Show
        Adrian Crum added a comment - The HTTP command OPTIONS should return information about the service in the response body - in the requested format.
        Hide
        Adrian Crum added a comment - - edited

        OFBiz services are based on the concept of Map In, Map Out. So the HTTP request and response bodies are nothing more than the Maps going into and out of the services. This simple approach leverages all of the existing OFBiz service documentation and web tools - there is no new API to learn.

        Representation handlers will convert the in/out Maps to various representations - HTML, XML, JSON, etc. Applications can implement custom representation handlers.

        XStream will be used for the XML representation:

        http://xstream.codehaus.org/converters.html

        Show
        Adrian Crum added a comment - - edited OFBiz services are based on the concept of Map In, Map Out. So the HTTP request and response bodies are nothing more than the Maps going into and out of the services. This simple approach leverages all of the existing OFBiz service documentation and web tools - there is no new API to learn. Representation handlers will convert the in/out Maps to various representations - HTML, XML, JSON, etc. Applications can implement custom representation handlers. XStream will be used for the XML representation: http://xstream.codehaus.org/converters.html
        Hide
        Adrian Crum added a comment -

        Updated POC configuration.

        Show
        Adrian Crum added a comment - Updated POC configuration.
        Hide
        Adrian Crum added a comment -

        A good candidate for a prototype could be the Webtools' "Entity Data Maintenance" application: we could rewrite it to work with RESTful URIs like

        webtools/entities/
        webtools/entities/orderheaders/
        webtools/entities/orderheaders?orderTypeId=SALES_ORDER
        webtools/entities/orderheaders/10010 (CRUD using GET/POST/DELETE)
        webtools/entityrelations/orderheader (this will return URLs of related entities)

        We could provide different representations for the responses (and this could also serve to reimplement the "XML data export" part).

        Show
        Adrian Crum added a comment - A good candidate for a prototype could be the Webtools' "Entity Data Maintenance" application: we could rewrite it to work with RESTful URIs like webtools/entities/ webtools/entities/orderheaders/ webtools/entities/orderheaders?orderTypeId=SALES_ORDER webtools/entities/orderheaders/10010 (CRUD using GET/POST/DELETE) webtools/entityrelations/orderheader (this will return URLs of related entities) We could provide different representations for the responses (and this could also serve to reimplement the "XML data export" part).
        Hide
        Adrian Crum added a comment - - edited

        We need a way to map REST URLs to the appropriate OFBiz services. This issue is for discussion/collaboration on adding REST request handling to the OFBiz project. The initial comments/design were taken from a discussion on the dev mailing list.

        The REST URLs (or URIs) should represent resources and the HTTP commands should represent actions taken on those resources. The generally accepted convention is that POST is a create operation, PUT is an update operation, GET returns the requested resource, and DELETE is a delete operation.

        A servlet will be developed that reads a configuration file which maps REST resource URLs to OFBiz services (POC configuration attached).

        REST Introduction: http://www.infoq.com/articles/rest-introduction
        A good example of a REST API: http://apidoc.adility.com/submission-api

        Show
        Adrian Crum added a comment - - edited We need a way to map REST URLs to the appropriate OFBiz services. This issue is for discussion/collaboration on adding REST request handling to the OFBiz project. The initial comments/design were taken from a discussion on the dev mailing list. The REST URLs (or URIs) should represent resources and the HTTP commands should represent actions taken on those resources. The generally accepted convention is that POST is a create operation, PUT is an update operation, GET returns the requested resource, and DELETE is a delete operation. A servlet will be developed that reads a configuration file which maps REST resource URLs to OFBiz services (POC configuration attached). REST Introduction: http://www.infoq.com/articles/rest-introduction A good example of a REST API: http://apidoc.adility.com/submission-api
        Hide
        Adrian Crum added a comment - - edited

        The attached files show how the Example component can support REST requests.

        Show
        Adrian Crum added a comment - - edited The attached files show how the Example component can support REST requests.

          People

          • Assignee:
            Unassigned
            Reporter:
            Adrian Crum
          • Votes:
            0 Vote for this issue
            Watchers:
            11 Start watching this issue

            Dates

            • Created:
              Updated:

              Development