Sorry I didn't respond to this earlier today, I had intended to.

What you're describing isn't REST, and the principles of REST are what have
been guiding the design of the new API so far. I see a lot of value in
using REST approaches, mostly around clarity of the interface.

While the idea of a very thin proxy seemed like a great idea at one point,
my conversations at the summit convinced me that there was value in both
using the client interfaces present in the openstack_dashboard/api code
base (since they abstract away many issues in the apis including across
versions) and also value in us being able to clean up (for example, using
"project_id" rather than "project" in the user API we've already
implemented) and extend those interfaces (to allow batched operations).

We want to be careful about what we expose in Horizon to the JS clients
through this API. That necessitates some amount of code in Horizon. About
half of the current API for keysone represents that control (the other half
is docstrings :)


     Richard


On Tue Dec 09 2014 at 9:37:47 PM Tihomir Trifonov <t.trifo...@gmail.com>
wrote:

> Sorry for the late reply, just few thoughts on the matter.
>
> IMO the REST middleware should be as thin as possible. And I mean thin in
> terms of processing - it should not do pre/post processing of the requests,
> but just unpack/pack. So here is an example:
>
> instead of making AJAX calls that contain instructions:
>
> ​​
>> POST --json --data {"action": "delete", "data": [ {"name":
>> "item1"}, {"name": "item2"}, {"name": "item3" ]}
>
>
> I think a better approach is just to pack/unpack batch commands, and leave
> execution to the frontend/backend and not middleware:
>
>
> ​​
>> POST --json --data {"
>> ​batch
>> ":
>> ​[
>> {​
>> "
>> ​
>> action"
>> ​ : "delete"​
>> ,
>> ​"payload": ​
>> {"name": "item1"}
>> ​,
>> {​
>> "
>> ​
>> action"
>> ​ : "delete"​
>> ,
>> ​
>> "payload":
>> ​
>> {"name": "item
>> ​2
>> "}
>> ​,
>> {​
>> "
>> ​
>> action"
>> ​ : "delete"​
>> ,
>> ​
>> "payload":
>> ​
>> {"name": "item
>> ​3
>> "}
>> ​ ] ​
>> ​
>> ​
>> }
>
>
> ​The idea is that the middleware should not know the actual data. It
> should ideally just unpack the data:
>
> ​​responses = []
>>
>
> for cmd in
>> ​ ​
>> ​
>> ​
>> request.POST['batch']:​
>
>
>> ​
>> ​​responses
>> ​.append(​
>> ​
>> getattr(controller, cmd['action']
>> ​)(**
>> cmd['​payload']
>> ​)​)
>>
>
>> ​return responses​
>>
>
>
> ​and the frontend(JS) will just send batches of simple commands, and will
> receive a list of responses for each command in the batch. The error
> handling will be done in the frontend​(JS) as well.
>
> ​
>
> For the more complex example of 'put()' where we have dependent objects:
>
> project = api.keystone.tenant_get(request, id)
>> kwargs = self._tenant_kwargs_from_DATA(request.DATA, enabled=None)
>> api.keystone.tenant_update(request, project, **kwargs)
>
>
>
> In practice the project data should be already present in the
> frontend(assuming that we already loaded it to render the project
> form/view), so
>
> ​
> ​
> POST --json --data {"
> ​batch
> ":
> ​[
> {​
> "
> ​
> action"
> ​ : "tenant_update"​
> ,
> ​"payload": ​
> {"project": js_project_object.id, "name": "some name", "prop1": "some
> prop", "prop2": "other prop, etc."}
> ​
> ​ ] ​
> ​
> ​
> }​
>
> So in general we don't need to recreate the full state on each REST call,
> if we make the Frontent full-featured application. This way - the frontend
> will construct the object, will hold the cached value, and will just send
> the needed requests as single ones or in batches, will receive the response
> from the API backend, and will render the results. The whole processing
> logic will be held in the Frontend(JS), while the middleware will just act
> as proxy(un/packer). This way we will maintain just the logic in the
> frontend, and will not need to duplicate some logic in the middleware.
>
>
>
>
> On Tue, Dec 2, 2014 at 4:45 PM, Adam Young <ayo...@redhat.com> wrote:
>
>>  On 12/02/2014 12:39 AM, Richard Jones wrote:
>>
>> On Mon Dec 01 2014 at 4:18:42 PM Thai Q Tran <tqt...@us.ibm.com> wrote:
>>
>>>  I agree that keeping the API layer thin would be ideal. I should add
>>> that having discrete API calls would allow dynamic population of table.
>>> However, I will make a case where it *might* be necessary to add
>>> additional APIs. Consider that you want to delete 3 items in a given table.
>>>
>>> If you do this on the client side, you would need to perform: n * (1 API
>>> request + 1 AJAX request)
>>> If you have some logic on the server side that batch delete actions: n *
>>> (1 API request) + 1 AJAX request
>>>
>>> Consider the following:
>>> n = 1, client = 2 trips, server = 2 trips
>>> n = 3, client = 6 trips, server = 4 trips
>>> n = 10, client = 20 trips, server = 11 trips
>>> n = 100, client = 200 trips, server 101 trips
>>>
>>> As you can see, this does not scale very well.... something to
>>> consider...
>>>
>>  This is not something Horizon can fix.  Horizon can make matters worse,
>> but cannot make things better.
>>
>> If you want to delete 3 users,   Horizon still needs to make 3 distinct
>> calls to Keystone.
>>
>> To fix this, we need either batch calls or a standard way to do multiples
>> of the same operation.
>>
>> The unified API effort it the right place to drive this.
>>
>>
>>
>>
>>
>>
>>
>>  Yep, though in the above cases the client is still going to be hanging,
>> waiting for those server-backend calls, with no feedback until it's all
>> done. I would hope that the client-server call overhead is minimal, but I
>> guess that's probably wishful thinking when in the land of random Internet
>> users hitting some provider's Horizon :)
>>
>>  So yeah, having mulled it over myself I agree that it's useful to have
>> batch operations implemented in the POST handler, the most common operation
>> being DELETE.
>>
>>  Maybe one day we could transition to a batch call with user feedback
>> using a websocket connection.
>>
>>
>>       Richard
>>
>>>  Richard Jones ---11/27/2014 05:38:53 PM---On Fri Nov 28 2014 at
>>> 5:58:00 AM Tripp, Travis S <travis.tr...@hp.com> wrote:
>>>
>>> From: Richard Jones <r1chardj0...@gmail.com>
>>> To: "Tripp, Travis S" <travis.tr...@hp.com>, OpenStack List <
>>> openstack-dev@lists.openstack.org>
>>> Date: 11/27/2014 05:38 PM
>>> Subject: Re: [openstack-dev] [horizon] REST and Django
>>>
>>> ------------------------------
>>>
>>>
>>>
>>>
>>> On Fri Nov 28 2014 at 5:58:00 AM Tripp, Travis S <*travis.tr...@hp.com*
>>> <travis.tr...@hp.com>> wrote:
>>>
>>>    Hi Richard,
>>>
>>>    You are right, we should put this out on the main ML, so copying
>>>    thread out to there.  ML: FYI that this started after some impromptu IRC
>>>    discussions about a specific patch led into an impromptu google hangout
>>>    discussion with all the people on the thread below.
>>>
>>>
>>> Thanks Travis!
>>>
>>>
>>>
>>>    As I mentioned in the review[1], Thai and I were mainly discussing
>>>    the possible performance implications of network hops from client to
>>>    horizon server and whether or not any aggregation should occur server 
>>> side.
>>>      In other words, some views  require several APIs to be queried before 
>>> any
>>>    data can displayed and it would eliminate some extra network requests 
>>> from
>>>    client to server if some of the data was first collected on the server 
>>> side
>>>    across service APIs.  For example, the launch instance wizard will need 
>>> to
>>>    collect data from quite a few APIs before even the first step is 
>>> displayed
>>>    (I’ve listed those out in the blueprint [2]).
>>>
>>>    The flip side to that (as you also pointed out) is that if we keep
>>>    the API’s fine grained then the wizard will be able to optimize in one
>>>    place the calls for data as it is needed. For example, the first step may
>>>    only need half of the API calls. It also could lead to perceived
>>>    performance increases just due to the wizard making a call for different
>>>    data independently and displaying it as soon as it can.
>>>
>>>
>>> Indeed, looking at the current launch wizard code it seems like you
>>> wouldn't need to load all that data for the wizard to be displayed, since
>>> only some subset of it would be necessary to display any given panel of the
>>> wizard.
>>>
>>>
>>>
>>>    I tend to lean towards your POV and starting with discrete API calls
>>>    and letting the client optimize calls.  If there are performance problems
>>>    or other reasons then doing data aggregation on the server side could be
>>>    considered at that point.
>>>
>>>
>>> I'm glad to hear it. I'm a fan of optimising when necessary, and not
>>> beforehand :)
>>>
>>>
>>>
>>>    Of course if anybody is able to do some performance testing between
>>>    the two approaches then that could affect the direction taken.
>>>
>>>
>>> I would certainly like to see us take some measurements when performance
>>> issues pop up. Optimising without solid metrics is bad idea :)
>>>
>>>
>>>     Richard
>>>
>>>
>>>
>>>    [1]
>>>    
>>> *https://review.openstack.org/#/c/136676/8/openstack_dashboard/api/rest/urls.py*
>>>    
>>> <https://review.openstack.org/#/c/136676/8/openstack_dashboard/api/rest/urls.py>
>>>    [2]
>>>    *https://blueprints.launchpad.net/horizon/+spec/launch-instance-redesign*
>>>    <https://blueprints.launchpad.net/horizon/+spec/launch-instance-redesign>
>>>
>>>    -Travis
>>>
>>>    *From: *Richard Jones <*r1chardj0...@gmail.com*
>>>    <r1chardj0...@gmail.com>>
>>> * Date: *Wednesday, November 26, 2014 at 11:55 PM
>>> * To: *Travis Tripp <*travis.tr...@hp.com* <travis.tr...@hp.com>>, Thai
>>>    Q Tran/Silicon Valley/IBM <*tqt...@us.ibm.com* <tqt...@us.ibm.com>>,
>>>    David Lyle <*dkly...@gmail.com* <dkly...@gmail.com>>, Maxime Vidori <
>>>    *maxime.vid...@enovance.com* <maxime.vid...@enovance.com>>,
>>>    "Wroblewski, Szymon" <*szymon.wroblew...@intel.com*
>>>    <szymon.wroblew...@intel.com>>, "Wood, Matthew David (HP Cloud -
>>>    Horizon)" <*matt.w...@hp.com* <matt.w...@hp.com>>, "Chen, Shaoquan" <
>>>    *sean.ch...@hp.com* <sean.ch...@hp.com>>, "Farina, Matt (HP Cloud)" <
>>>    *matthew.far...@hp.com* <matthew.far...@hp.com>>, Cindy Lu/Silicon
>>>    Valley/IBM <*c...@us.ibm.com* <c...@us.ibm.com>>, Justin
>>>    Pomeroy/Rochester/IBM <*jpom...@us.ibm.com* <jpom...@us.ibm.com>>,
>>>    Neill Cox <*neill....@ingenious.com.au* <neill....@ingenious.com.au>>
>>> * Subject: *Re: REST and Django
>>>
>>>    I'm not sure whether this is the appropriate place to discuss this,
>>>    or whether I should be posting to the list under [Horizon] but I think we
>>>    need to have a clear idea of what goes in the REST API and what goes in 
>>> the
>>>    client (angular) code.
>>>
>>>    In my mind, the thinner the REST API the better. Indeed if we can
>>>    get away with proxying requests through without touching any *client 
>>> code,
>>>    that would be great.
>>>
>>>    Coding additional logic into the REST API means that a developer
>>>    would need to look in two places, instead of one, to determine what was
>>>    happening for a particular call. If we keep it thin then the API 
>>> presented
>>>    to the client developer is very, very similar to the API presented by the
>>>    services. Minimum surprise.
>>>
>>>    Your thoughts?
>>>
>>>
>>>         Richard
>>>
>>>
>>>    On Wed Nov 26 2014 at 2:40:52 PM Richard Jones <
>>>    *r1chardj0...@gmail.com* <r1chardj0...@gmail.com>> wrote:
>>>
>>>
>>>     Thanks for the great summary, Travis.
>>>
>>>       I've completed the work I pledged this morning, so now the REST
>>>       API change set has:
>>>
>>>       - no rest framework dependency
>>>       - AJAX scaffolding in openstack_dashboard.api.rest.utils
>>>       - code in openstack_dashboard/api/rest/
>>>       - renamed the API from "identity" to "keystone" to be consistent
>>>       - added a sample of testing, mostly for my own sanity to check
>>>       things were working
>>>
>>>       *https://review.openstack.org/#/c/136676*
>>>       <https://review.openstack.org/#/c/136676>
>>>
>>>
>>>             Richard
>>>
>>>       On Wed Nov 26 2014 at 12:18:25 PM Tripp, Travis S <
>>>       *travis.tr...@hp.com* <travis.tr...@hp.com>> wrote:
>>>
>>>
>>>     Hello all,
>>>
>>>          Great discussion on the REST urls today! I think that we are
>>>          on track to come to a common REST API usage pattern.  To provide 
>>> quick
>>>          summary:
>>>
>>>          We all agreed that going to a straight REST pattern rather
>>>          than through tables was a good idea. We discussed using direct get 
>>> / post
>>>          in Django views like what Max originally used[1][2] and Thai also
>>>          started[3] with the identity table rework or to go with 
>>> djangorestframework
>>>          [5] like what Richard was prototyping with[4].
>>>
>>>          The main things we would use from Django Rest Framework were
>>>          built in JSON serialization (avoid boilerplate), better exception 
>>> handling,
>>>          and some request wrapping.  However, we all weren’t sure about the 
>>> need for
>>>          a full new framework just for that. At the end of the 
>>> conversation, we
>>>          decided that it was a cleaner approach, but Richard would see if 
>>> he could
>>>          provide some utility code to do that much for us without requiring 
>>> the full
>>>          framework.  David voiced that he doesn’t want us building out a 
>>> whole
>>>          framework on our own either.
>>>
>>>          So, Richard will do some investigation during his day today
>>>          and get back to us.  Whatever the case, we’ll get a patch in 
>>> horizon for
>>>          the base dependency (framework or Richard’s utilities) that both 
>>> Thai’s
>>>          work and the launch instance work is dependent upon.  We’ll build 
>>> REST
>>>          style API’s using the same pattern.  We will likely put the rest 
>>> api’s in
>>>          horizon/openstack_dashboard/api/rest/.
>>>
>>>          [1]
>>>          
>>> *https://review.openstack.org/#/c/133178/1/openstack_dashboard/workflow/keypair.py*
>>>          
>>> <https://review.openstack.org/#/c/133178/1/openstack_dashboard/workflow/keypair.py>
>>>          [2]
>>>          
>>> *https://review.openstack.org/#/c/133178/1/openstack_dashboard/workflow/launch.py*
>>>          
>>> <https://review.openstack.org/#/c/133178/1/openstack_dashboard/workflow/launch.py>
>>>          [3]
>>>          
>>> *https://review.openstack.org/#/c/133767/8/openstack_dashboard/dashboards/identity/users/views.py*
>>>          
>>> <https://review.openstack.org/#/c/133767/8/openstack_dashboard/dashboards/identity/users/views.py>
>>>          [4]
>>>          
>>> *https://review.openstack.org/#/c/136676/4/openstack_dashboard/rest_api/identity.py*
>>>          
>>> <https://review.openstack.org/#/c/136676/4/openstack_dashboard/rest_api/identity.py>
>>>          [5] *http://www.django-rest-framework.org/*
>>>          <http://www.django-rest-framework.org/>
>>>
>>>          Thanks,
>>>
>>>
>>>     Travis_______________________________________________
>>>          OpenStack-dev mailing list
>>>          OpenStack-dev@lists.openstack.org
>>>
>>>          http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>>
>>>
>>>  _______________________________________________
>>> OpenStack-dev mailing list
>>> OpenStack-dev@lists.openstack.org
>>> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>>
>>
>>
>> _______________________________________________
>> OpenStack-dev mailing 
>> listOpenStack-dev@lists.openstack.orghttp://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>
>>
>>
>> _______________________________________________
>> OpenStack-dev mailing list
>> OpenStack-dev@lists.openstack.org
>> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>
>>
>
>
> --
> Regards,
> Tihomir Trifonov
>  _______________________________________________
> OpenStack-dev mailing list
> OpenStack-dev@lists.openstack.org
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>
_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

Reply via email to