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 21:42:17 GMT
On Tue, Jul 16, 2013 at 12:55 PM, Erin Noe-Payne
<erin.noe.payne@gmail.com>wrote:

> In terms of implementation, I will definitely be interested to see how
> the fields selector works.
>
> With respect to response format, all responses will be wrapped in the
> same way. Will it make sense to create a custom "ApiResponse" class or
> something of the sort that represents the wrapper. Alternatively could
> cxf's outgoing interceptors be used to reformat the data response?
> Same thing for errors.
>

I don't think we can do this with an interceptor because we would still
need to communicate to the interceptor the data (total records....) so we
might as well just wrap the responses.

I was going to model the fields implementation after what we do for Shindig
since they already have the fileds concept.

>
>
> On Tue, Jul 16, 2013 at 2:22 PM, Erin Noe-Payne
> <erin.noe.payne@gmail.com> wrote:
> > On Tue, Jul 16, 2013 at 1: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)
> >>  - 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.
> >
> > +1 to all of the above
> >
> >>  - What is the full meta structure we want to return?
> >
> > So this can be fluid. In the case of lists (search or list endpoints)
> > it should definitely contain pagination and count data. In the case of
> > individual resources it does not necessarily need to contain anything.
> > As long as we have the wrapped object then we have the key reserved to
> > attach metadata as the need arises. One example of what we could use
> > it for is to contain link information. I.E. a request to /page/1
> > returns a flat resource, without the regions. Then meta could look
> > like:
> >
> > {
> >   "meta": {
> >     "regions": "http://localhost:8080/portal/api/page/1/regions",
> >     ...
> >   }
> > }
> >
> >>
> >>
> >>>
> >>> 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