Oh boy!! :) Comments inline
On Thu, Jul 11, 2013 at 1:20 PM, Erin Noe-Payne <[email protected]>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 > > 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) > > 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. > > 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? > > 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. > > GET /people/1 > { > meta: { ... }, > data: { id: 1, name: 'canonical', email: '[email protected]', ... } > } > > 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? >
