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 Tue, 16 Jul 2013 17:53:35 GMT
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)
 - 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