Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API verb and GET query patterns #5

Open
onthebreeze opened this issue Jun 15, 2019 · 9 comments
Open

API verb and GET query patterns #5

onthebreeze opened this issue Jun 15, 2019 · 9 comments

Comments

@onthebreeze
Copy link
Contributor

Starting this issue as a discussion forum for how we should model and generate API behaviour for verbs (GET, POST, PATCH, PUT) and GET collection query parameters.

My suggestion, using the Voyages <<interface>> from the attached sample diagram

POST:
UML representation is an Operation POST(Voyage) in the Voyages interface.

  • API request becomes POST /Voyages with body = voyage JSON structure (WITHOUT the attributes of the voyages interface class - because they are created by the POST action).
  • API success response is 201 "created" with body = the created voyage JSON structure (WITH the attributes of the voyages interface class).

GET:
Represented as parameters in operations in the UML interface class. The parameters MUST have the name of the attribute in the resource model that will be used as the filter. The UML type of the parameter SHOULD be set to the UML class that has the filter attribute.

  • if the parameter "id" is listed, this is implemented as a GET instance path. API request becomes GET /Voyages/id
  • all other parameters are represented as URL query parameters - eg GET /Voyages?Unlocode=AUBNE.
  • if any parameters of are a date type then we should generate two API query parameter - one with "before_" prefix and the other with "after_" prefix. eg GET /Voyages?before_OccurrenceTime=01-06-2019
  • API success response is 200 "ok" with the Voyage JSON structure plus attributes of interface class.

PATCH:

Same as POST except that {id} must be specified in the path PATCH /Voyages/id/ body of JSON voyage structure.

CompleteExample

@chadgates
Copy link

On the GET request and dates, I would prefer a "from_" and "to_" kind of prefix. "Before_" suggest to me <"2019-06-01", so implicitly stating <="2019-05-31". I feel that defining a range for dates is better than < or > statements. Or open the option to do both, similar to some frameworks out there stating:
"gt" = greater than / "lt" = less than
"gte" = greater than or equal / "lte" = less than or equal
as parameters.
That would make it more generic, than "before" and "after" and could be used on none-date fields as well.

Also wonder about the "unlocode" part of this: GET /Voyages?Unlocode=AUBNE. I think it is not clear which Unlocode this would be referred to, assuming that it could exist in something else related to the model but not the "LogisticsLocation". Example: Name. GET/Voyages?Name="1111". Which name should be considered? Should there be a definition on how these "related object fields" are named so that it is clear, which one this refers to?

@onthebreeze
Copy link
Contributor Author

onthebreeze commented Jun 20, 2019

Hi Chad - thanks for the feedback. Agree on the from/to and will reflect that in the spec. Also the use of operators on query parameters is an interesting direction and worth consideration - but probably not in this UML profile spec and maybe in the OpenAPI NDR (not yet written - but will contain all those best practices for JSON APIs.

On the question on what exactly the attribute like "unlocode" applies to - in the actual UML model it is possible to link the operation parameter to a class so if you look closely at the model it will indicate that unlocoode GET parameter is the attribute of TransportLocation. Having said that - this is only in the model and the generate spec just says "unlocode". I can see a couple of choices:

  • Leave it as it is but just do a better job of documentation so that the generated spec has words to say what that parameter means. Easy to do.
  • Update the generation rules so that the OpenAPi parameter is qialified with the class name like GET /voyages?transportlocation-unlocode=AUBNE. Also easy to do.

THoughts?

@onthebreeze
Copy link
Contributor Author

I've requested a tweak to the free API generator gs-gs/staruml-cefact#16 per your suggestion.

@chadgates
Copy link

I would vote for the later option:

Update the generation rules so that the OpenAPi parameter is qialified with the class name like GET /voyages?transportlocation-unlocode=AUBNE. Also easy to do.

@onthebreeze
Copy link
Contributor Author

onthebreeze commented Jun 20, 2019

Actually - thinking about it a bit more, a standard way to represent more complex queries in URL strings could be handy. but I'm struggling to find a really solid reference. There are some good posts like this one https://stackoverflow.com/questions/40618327/how-to-design-generic-filtering-operators-in-the-query-string-of-an-api . Also there are some older specs like this https://github.com/persvr/rql. Any thoughts? Obviously https://graphql.org/ is getting pretty popular these days but that is a much more than a few extra options in a REST query string...

@onthebreeze
Copy link
Contributor Author

for example:

  • GET /voyages?transportevent.occurence+gt=2019-06-20 ? or
  • GET /voyages?gt(transportevent.occurence,2019-06-20) or
  • some other way to represent it?

@chadgates
Copy link

After reading the stackoverflow articules (thanks for that reference!), I lean towards your example 1 (being example 2 in stackoverflow). It seems simple enough to read and parse and operator is just an "extension" that can or cannot be used:
GET /voyages?transportevent.occurence+gt=2019-06-20 -> providing you everything greater than
GET /voyages?transportevent.occurence=2019-06-20 -> providing you equal on that date, to be represented same as :
GET /voyages?transportevent.occurence+eq=2019-06-20, if eq became an operator.

@onthebreeze
Copy link
Contributor Author

onthebreeze commented Jun 20, 2019

Agreed - simple is good. Lets leave it at that then.

  • parameters will be prefixed by classname - so transportEvent.occurrence not just occurrence.
  • in the OpenAPI NDR will will specify a simple set of query operators like lt, gt, etc. Dont think the UML profile needs to mention them - just implied that these are allowed if the implementer wants to claim compliance with the OpenAPi NDR.

@monkeypants
Copy link

I'm indifferent to the . and + syntax, because I am accustomed to single ("under", _) and double underscore ("dunder", __) syntax, but I definitely agree that filters with "class_attribute__operator" pattern are the most straightforward comfortable pattern that I've encounted in the wild.

The list of comparison operators (gt, lt, eq) should be pretty uncontroversial, since they have been used consistently in unix tools for many decades. Increasing specaficity from left->right feels natural because that's how numbers work (and dates, in many parts of the world)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants