rave-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Geer <ch...@cxtsoftware.com>
Subject Re: [Proposal] REST API interface
Date Wed, 17 Jul 2013 02:04:11 GMT
On Tue, Jul 16, 2013 at 6:20 PM, Matt Franklin <m.ben.franklin@gmail.com>wrote:

> On Tue, Jul 16, 2013 at 12:53 PM, Chris Geer <chris@cxtsoftware.com>
> wrote:
>
> > On Tue, Jul 16, 2013 at 10:32 AM, Erin Noe-Payne
> > <erin.noe.payne@gmail.com>wrote:
> >
> > > Any further discussion here? I would like to start implementing more
> > > of the REST APIs, as it is foundational for the entire angular
> > > architecture.
> > >
> > > My understanding from Matt is that the current apis in trunk are
> > > mostly proof of concept - they are not tested and much of the
> > > functionality is just stubbed. Are any of the rest api implementations
> > > in the code base a good working example? Is there other documentation
> > > we can reference?
> > >
> >
> > I've been working on the People resource as a "reference" of how I'd like
> > to see them done but it's still a work in progress. I need to go back and
> > pull out the JSONView stuff and reimplement the "fields" concept. Couple
> of
> > notes:
> >
> >  - Object representations should be as flat as possible
> > and separate requests should be made to nested resources to get nested
> > details (i.e. if you have regions and regions/1/regionwidgets, the
> regions
> > representation should not contain an array of regionwidgets)
> >
>
> I am concerned about the round trips to support this when rendering the
> page.  With any page that has a sufficient number of gadgets, adding to the
> number of requests becomes problematic.
>

I agree and still thinks its required. We need to make sure that the
representation we present with GET is the same one we accept with PUT. So
if we want Page to return a rich document, then it should accept a rich
document which would eliminate the need for separate resources for
Regions/RegionsWidgets....

Erin, won't Angular help with this with caching?

>
>
> >  - All methods should return standard HTTP codes. We should document this
> > further on the wiki to make sure we all do the same way.
> >  - We won't accept partial updates with PUT, we will eventually add PATCH
> > to support that in the future
> >  - If the "fields" query attribute isn't included in a GET then all
> fields
> > are returned.
> >  - What is the full meta structure we want to return?
> >
> >
> > >
> > > On Thu, Jul 11, 2013 at 5:48 PM, Erin Noe-Payne
> > > <erin.noe.payne@gmail.com> wrote:
> > > > On Thu, Jul 11, 2013 at 5:02 PM, Matt Franklin <
> > m.ben.franklin@gmail.com>
> > > wrote:
> > > >> +1 for every one of Chris' +1s, unless otherwise noted.
> > > >>
> > > >> On Thu, Jul 11, 2013 at 3:47 PM, Chris Geer <chris@cxtsoftware.com>
> > > wrote:
> > > >>
> > > >>> Oh boy!! :)
> > > >>>
> > > >>> Comments inline
> > > >>>
> > > >>>
> > > >>> On Thu, Jul 11, 2013 at 1:20 PM, Erin Noe-Payne <
> > > erin.noe.payne@gmail.com
> > > >>> >wrote:
> > > >>>
> > > >>> > Hey All,
> > > >>> >
> > > >>> > As we are starting to look at the rest apis in more detail,
I
> would
> > > >>> > like to discuss and agree upon a consistent interface for
our
> apis.
> > > >>> > We currently have several developers interested in contributing
> to
> > > the
> > > >>> > apis and the angular branch, and I would like to solidify
the
> > > >>> > interface, methods, response format, etc so that we can be
on the
> > > same
> > > >>> > page going forward. If we can agree on an api virtualization
> layer
> > > >>> > then we should be able to build against it on the server
and on
> the
> > > >>> > angular application in parallel.
> > > >>> >
> > > >>> > I'll start with a proposal and look for feedback to iterate
from
> > > there.
> > > >>> >
> > > >>> > 1. API root url
> > > >>> >
> > > >>> > "/api". Drop support for rpc api, move from /api/rest to
just
> /api.
> > > >>> >
> > > >>>
> > > >>> +1 - the only downside of this is that it prohibits implementing
> over
> > > time
> > > >>> and requires a rip/replace approach of the whole system
> > > >
> > > > Well the development in trunk can continue to happen on /rest.
> Angular
> > > > (aka the consuming client for most of these apis) is already
> happening
> > > > in a branch, so those changes can be treated as a rip / replace
> > > > easily.
> > > >
> > > >>>
> > > >>> >
> > > >>> > 2. Media Types
> > > >>> >
> > > >>> > Initially support only application/json. We can revisit
> > > >>> > application/xml as a nice-to-have.
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 3. HTTP Methods
> > > >>> >
> > > >>> > GET, PUT, POST, DELETE
> > > >>> >
> > > >>>
> > > >>> +1 (We also need to decide if PUT can handle partial updates)
> > > >>>
> > > >>
> > > >> I say not.  That is what PATCH is for, once everything supports it:
> > > >> http://tools.ietf.org/html/rfc5789
> > > >
> > > > My understanding is that PUT should always be a full object replace.
> A
> > > > quick search returns the suggestion to use PATCH, or to use POST to a
> > > > subresource with a 303 response.
> > > >
> > > >>
> > > >>>
> > > >>> >
> > > >>> > 4. Status Codes
> > > >>> >
> > > >>> > 200, 201, 400, 401, 403, 404, 500
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 5. URL formats
> > > >>> >
> > > >>> > Use plural nouns (pages, people, widgets). Do not nest
> associations
> > > >>> > beyond one level deep. For example:
> > > >>> > /pages/1/regions (ok)
> > > >>> > /pages/1/regions/2/regionwidgets (not ok)
> > > >>> > /regions/2/regionwidgets (ok)
> > > >>> >
> > > >>>
> > > >>> I'm not a fan of this requirement. Your example is the exact reason
> > > I'm not
> > > >>> a fan actually. In all reality, regions don't mean anything
> outside a
> > > page,
> > > >>> and region widgets don't mean anything outside of a region. Yes,
> they
> > > have
> > > >>> IDs, but in reality, those IDs should be subordinate to the parent
> > (so
> > > >>> there should be nothing wrong with having Page 1 with regions
[1,2]
> > and
> > > >>> Page 2 with regions [1,2]). I understand that's not how the DB
> works
> > > today
> > > >>> but it's what makes the most logical sense.
> > > >>>
> > > >>
> > > >> I agree with Chris. We should not limit to a single level. That is
> > > counter
> > > >> to a few REST web service principles.
> > > >>
> > > >
> > > > Fair enough. In this case I guess I would just be looking for
> > > > consistency - will associations be infinitely nest-able. If not, what
> > > > is the rule to determine where we support more or less deeply nested
> > > > associations.
> > > >
> > > >>
> > > >>> >
> > > >>> > 6. Response formats
> > > >>> >
> > > >>> > 6a. Wrap all responses in an object. All valid (200) responses
> > should
> > > >>> > be wrapped in an object that includes a "meta" object for
> metadata,
> > > >>> > and a "data" object for the response body. This allows us
to
> > capture
> > > >>> > or extend metadata associated with a response as needed.
Any
> > metadata
> > > >>> > properties should be standardized.
> > > >>> >
> > > >>> > Example:
> > > >>> >
> > > >>> > GET /people
> > > >>> > {
> > > >>> >  meta: {count: 253, limit: 10, offset: 0, ...}
> > > >>> >  data: [ {id: 1, name: 'canonical', ...}, ... ]
> > > >>> > }
> > > >>> >
> > > >>> > GET /people/1
> > > >>> > {
> > > >>> >  meta: { ... }
> > > >>> >  data: {id:1, name: 'canonical', ...}
> > > >>> > }
> > > >>> >
> > > >>>
> > > >>> This really complicates a couple things, first, it means the GET
!=
> > PUT
> > > >>> since the GET will include the meta data. Can we achieve this
same
> > > result
> > > >>> with HTTP Headers?
> > > >>>
> > > >
> > > > We could possibly achieve the same with HTTP headers. I prefer the
> > > > object approach for clarity, since custom http headers are less
> > > > accessible or discoverable than object structure. I get your point,
> > > > but I see the wrapped object approach used commonly in major apis. If
> > > > it's clearly documented and used consistently across the entire api I
> > > > don't really see an issue.
> > > >
> > > >>> >
> > > >>> > 6b. Error objects. In the case of an error, the correct error
> code
> > > >>> > should be returned. In addition, an error object should be
> returned
> > > >>> > with a standardized format. Ideally including a verbose,
> > > >>> > human-readable error message for developers, and an
> > internationalized
> > > >>> > readable error message for display to end users.
> > > >>> >
> > > >>> > GET /people/25
> > > >>> > 401
> > > >>> > {
> > > >>> >  developerMessage: 'Unauthorized. Access to this resource
> requires
> > > >>> > authentication',
> > > >>> >  userMessage: 'Please login',
> > > >>> >  stackTrace: ...
> > > >>> > }
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 6c. Partial responses. By default all responses, whether
a list
> or
> > > >>> > individual resource, should return a full representation
of the
> > > >>> > resources (not including security constraints).  All endpoints
> > should
> > > >>> > support the query string parameter "fields", which accepts
a
> comma
> > > >>> > delimited list of fields to build a partial response.
> > > >>> >
> > > >>>
> > > >>> Hmmm.....what's funny (except for the wasted work) is this is
how I
> > > >>> originally  built the people resource. I changed it because the
> > > "fields"
> > > >>> approach gets almost impossible to manage with nested elements
(at
> > > least in
> > > >>> Java - rewrite in Ruby anyone??). I'm open to suggestions though.
I
> > > guess
> > > >>> we could also make a rule that the data objects shouldn't have
> nested
> > > >>> elements but that is a tough rule.
> > > >>>
> > > >>
> > > >> I think the fields approach makes sense long-term; but, it is not
> > > critical.
> > > >>
> > > >>
> > > >
> > > > I don't really know what the implementation looks like. If you allow
> > > > field filtering only on properties and deliver only properties (i.e.
> > > > no nested objects / associations) then I would assume it is pretty
> > > > straightforward.
> > > >>>
> > > >>> >
> > > >>> > GET /people/1
> > > >>> > {
> > > >>> >  meta: { ... },
> > > >>> >  data: { id: 1, name: 'canonical', email: 'canonical@gmail.com',
> > > ... }
> > > >>> > }
> > > >>> >
> > > >>> > GET /people/1?fields=id,name
> > > >>> > {
> > > >>> >  meta: { ... },
> > > >>> >  data: { id: 1, name: 'canonical' }
> > > >>> > }
> > > >>> >
> > > >>> > 6d. Pagination. All requests that return a list should be
> > paginated.
> > > >>> > The query string parameters "limit" and "offset" should be
used
> for
> > > >>> > pagination. On any request in which either parameter is not
set,
> > they
> > > >>> > should default to 10 and 0 respectively.
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 6e. Use camelCase for properties.
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 7. Endpoints.
> > > >>> >
> > > >>> > 7a. Standard endpoints: there should be standard CRUD endpoints
> to
> > > >>> > support each rave resource. In other words, any operation
> possible
> > in
> > > >>> > rave should be possible through a rest api action.
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> > 7b. Special endpoints. In the case of certain client needs,
we
> can
> > > >>> > implement a small number of special endpoints to fulfill
a
> specific
> > > >>> > role. The primary case in point is retrieving a page for
render,
> > > which
> > > >>> > returns a page, its regions, its regionWidgets, and their
render
> > > data.
> > > >>> >
> > > >>>
> > > >>> +1
> > > >>>
> > > >>> >
> > > >>> >
> > > >>> >
> > > >>> > Ok, I think that's it. This is meant as a proposal only -
we are
> > > >>> > looking for feedback to go forward. Thoughts?
> > > >>> >
> > > >>>
> > >
> >
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message