LiveRamp / reslang

A language for describing resource-oriented APIs & turning them into Swagger or resource diagrams. Oriented around the concepts we want to expose in the APIs.
Apache License 2.0
23 stars 7 forks source link

Allow MULTIGET for singletons and bulk for subresources #58

Closed dimatkach closed 4 years ago

dimatkach commented 4 years ago

I know multi get for singleton sounds weird, but hear me out :)

Here is a use case:

resource Pipeline {
   id: int
   name: string
   foo: bar

   /operations GET POST
}

struct PipelineStatus {
    started: date
    completed: date
    status: string
}

singleton subresource Pipeline::History {
    history: PipelineStatus[] output
    /operations MULTIGET
}

This (with the changes in this PR) does exactly what I need:

  1. The url looks correct: GET /v1/pipelines/${id}/history
  2. The response looks good:
    {
    "history": [ {
      "started": "2000-01-01",
      "completed": "2000-01-02",
       "status": "crashed_and_burned"
    }]
    }

The only problem is MULTIGET is not allowed for singletons (this is what the PR is changing). If History was not a singleton, it would need to have an id (does not make sense), which could be addressed fairly easily (not require an id for resources that don't have a GET), but even then:

  1. The url looks weird: GET /v1/pipelines/${id}/histories (plural???)
  2. Response is even worse:
    "histories": [{
       "history": { ... }
    }]

So, I thought, making history a singleton seems to address all three of the problems nicely: singletons don't have ids, they don't need to be pluralized, and they do not need to be wrapped into arrays. It seems to do exactly what I need here.

Another use case is a Find function:

    resource-level singleton subresource Pipeline::Find {
       foo: string queryonly
       pipeline: value-of Pipeline[] output
       /operations MULTIGET
   }

It is another example of a subresource that takes advantage of MULTIGET, but it is also resource-level (this is another change in this PR to allow this), so that it does not need parent id in the url.

This also generates exactly the API that makes sense.

Alternatively, I could model this as a (resource-level) action, but that again does not make very much sense and seems like a kludge, because Find is not really acting on the resource, so the url /v1/pipelines/actions/find does not look right at all.

liveandrew commented 4 years ago

just a couple of questions for my clarification. for the first one, don't you get the same thing with a GET?

singleton subresource Pipeline::History { history: PipelineStatus[] output /operations GET }

/v1/pipelines/${id}/history

if you need query params for the GET, mark the params "representation"

liveandrew commented 4 years ago

for the find, can't you just do it as a query param on the actual pipeline itself?

resource Pipeline { foo: string queryonly /operations MULTIGET }

?

dimatkach commented 4 years ago

@liveandrew Excellent, thanks! It is just what I needed. Looks like a lot of "overthinking" on my part. Thanks for the suggestions!

liveandrew commented 4 years ago

ah, thanks so much Dima! thanks for being one of the deepest users of reslang at LR!