-
Notifications
You must be signed in to change notification settings - Fork 147
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
RESTful API design #582
Comments
'Member' vs. 'admin' functionalityAlmost all users want to order with a foodcoop, and many users perform tasks within the foodcoop, of which some need 'admin'-access (like updating member details, editing orders, creating financial transactions, etc.). We'd like to be able to do all of this using the API. When a member is ordering for himself, he only needs to see the articles in the currently open orders. He only must update group order articles for his ordergroup. When viewing his ordergroup's account statement, he should only see the ones for his ordergroup (not others). But when doing a workgroup tasks, someone in the orders workgroup needs to see all members' group order articles, and someone doing finances must be able to see all (relevant) member's transactions. How does this difference between 'member' and 'admin' functionality work in the API? Let the client work it outIf the client knows which access rules apply, it can give the desired query parameters. So only show open orders in the member ordering app. Only show the ordergroup's group order articles. In the boxfill phase, only allow updating group order articles that result in equal or more order result, and check minimum balance in the front-end as well. Putting these checks in the front-end is highly undesirable. There must be some way for the API to enforce member-related checks, but allow admins to modify things that members can't. (Note: It may be possible to avoid we the issues mentioned here -- by not allowing admins to update a group order article's quantity and tolerance, only the result -- but the general idea that an admin-as-member may have different behaviour than admin still holds, even if we may happen to be able to avoid it right now.) Access token scopesAuthorization can (and must) happen by access token scope. The default scope would be members-only, which is what front-end apps use when doing things 'as a member'. Admin applications would request the scope applicable for what it needs to do. If there would be a single app with both member and admin functionality, it would need to handle different access tokens and make sure to use the correct one. I haven't seen this pattern elsewhere, and I can see client developers accidentaly choosing the wrong access token. Scope as query parameterUse a query parameter to indicate if one would want to do something as 'member' or as 'admin' (SO idea). Default would be 'member', I guess. Different endpointsMember-related endpoints only return the member's and ordergroup's records, admin-related endpoints work on all records. Authorization is different for both, but they return the same objects (except for fields that may be visible for admins only). This would result in some code duplication, because there are basically two APIs (controllers, docs, specs - models and serializers can be shared). |
Regarding 'member' vs. 'admin', I propose to use access token scopes.
This allows us to have clear API endpoints, and start implementing the member-part without being in the way for admin-parts. |
ScopesThis is a list to get started. As the API develops, we may want to add or refine some scopes (e.g. currently the finance permission allows financial transactions, bank accounts and balancing, but since balancing works on orders and group orders, perhaps it's better to split that, not sure - let's not worry too much until we start implementing that, if ever).
Note that any The Endpoint URLsLists endpoints with required scopes. (#) = while accessible with multiple scopes, the admin scope would typically return more information than the member scope.
Allright, I guess the rest would speak for itself / will become clear during development. |
I personally like the "Let the client work it out" approach combined with "Access token scopes" the most. IMHO all endpoints must return the same structure of data: users with less privileges only get a subset of the data. I don't like the difference between PS: I also don't like the idea of 'admin' and 'member' apps. I personally like to work on one uniform Foodsoft application, which implements everything in the (far) future. |
Yes.
My terminology is perhaps confusing. I mean that there are different roles. All members want to order, look at the list of users, send messages, etc. Then most people will also be in a workgroup, and when performing a task as a member of that workgroup (like creating an order, or entering financial transactions, or dividing extra articles over members), what the API allows is different. So one accesses the API with a certain role, and depending on the API, you are or are not allowed to do certain things. So even when you are capable of having the managing-orders role, when you order articles like all members, this happens as role 'regular member'. The access token scopes can function as selecting roles for a task.
That could be a useful angle. With clear descriptions of what they mean (like
From an end-user perspective, yes. Internally it could be different apps sharing the same layout. But that's an implementation detail, I think. |
i would be careful about simplicity in your rest api design that sacrifices simplicity in implementation. aside from a few geeks like ourselves, nobody is looking at the rest api routes, so even if the resource mapping is so elegant that there are the smallest number of routes (and much more logic in the controller and things that consume this rest data), it won't be appreciated by many, and i think even the developer will hate the bugs it can create. (i speak from my experience working with spree/solidus and the mess that they made in this manner) so, my suggestion in terms of api design is for more routes so you can keep each controller a very simple 'crud' with no logic or checking. for an access policy, specify which roles can access which routes (and what methods on that route) rather than changing the content returned depending on the role. (for code simplicity and client/consumer simplicity). yes, you will have more routes, but you can make more assumptions about the response from those routes, which keeps client code simpler, and less checking inside the controller (you are allowed or not). |
also, i like the scoped access levels and i agree the current (old) rules aren't fine grained enough. for example, having 'finance' access lets you not only settle an order, but also record that someone paid some money to the coop. but maybe in some coop that is fine and we all know that few coops work in the same way. in practice it hasn't been a problem because every finance change has someones name on it (which is great). |
What about using There will probably be a small number of places left where the 'general' endpoints (not scoped by [This was inspired by GraphQL, where often |
Another scopes proposalI'm trying to integrate my and @paroga's ideas in how we'd use scopes. It's probably not perfect yet. Two options follow. Existing rolesUse the existing roles:
More or less per resourceIf we want more granularity, something like this could could make sense.
Scopes marked with (default) are included in the default scopes and require no extra permissions (through workgroups). Perhaps it is also useful to include a 'default' scope that can be added to include the default scopes when adding another one. Note that some data where scopes are needed, may still be accessible to the user (but then only a portion of it). For example, it makes sense to include article data in the order_articles endpoint (because you'd usually want to show the article name, for example). (&) Do we need some restriction of modifying workgroups with more permissions than the logged-in user? |
sorry for the delay replying. other work got busy, but i want my co-op up to the latest version so i can help more effectively on the api. ACL is a very hard to get right. it'll often end up nearly right, and then people start to hack around it to get reasonable use cases working. i saw this in spree - where they started using cancan but then quickly the controllers became littered with logic that was checking whether something was allowed or not. the net result was a real mess. i think your scopes above seem reasonable. i presume the intention is to take these scopes and then tell doorkeeper to enforce them via https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes#using-in-your-api i would guess that you won't be finished working on the scopes until you have finished working on the api. so, the best thing you can get perfect now is trying to define a consistent/extensible approach. i also think you are right that simplicity to understand it is really one of the main goals. and having an agreed way to customise security per co-op would be useful (ie, extensibility/customisation in a way that doesn't prevent applying upgrades) |
Thanks for your input, @carchrae. I hope we can integrate your contributions into mainline Foodsoft sometime. What would you choose: role-based vs. ~resource-based, or something more in-between?
Do you have a concrete example, perhaps, to explain what is meant here? |
would it make sense to specify some Are financial_transactions ordered by (autoincrement) id? and never edited? |
@wvengen - i am curious, do you know if anyone is currently using the api for a vue/react app? i have heavily customised the ordering page and balancing page, but using rails templates and scraps of javascript. i would much rather do that with front-end js code. i am reasonably proficient with vue. i think it probably takes building a full feature ui to really tease out all the details needed from the api. |
@carchrae I don't really have an overview, but know that the financial transactions are being used. The rest hasn't really been merged yet (but I plan to do so in the next weeks), so I guess that is hasn't been used very widely yet. I vaguely remember hearing from one or two people that they were using it. But the (to be merged) API should be ready to do member ordering - foodsoft-shop uses it. |
@orangeman what is your use-case? |
thanks @wvengen. i will try out the api when i try to get our coop's site back up to date (and will submit some other PRs). not clear on when i will find time to do that, but i'd like to improve a few pages |
@wvengen usecase eg keeping data in sync with other systems like
accounting or offline apps
…On 1/28/21 7:25 PM, wvengen wrote:
@orangeman <https://github.com/orangeman> what is your use-case?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#582 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAGOHJIVHGMYJI4ZGTLK3LS4GTZJANCNFSM4F6CDDVA>.
|
@orangeman that makes sense; for real-time updates I hope someday something with websockets could be used (so that e.g. when the order is closing soon, members can see real-time updates when ordering), for offline syncing some standard parameter (like |
Good point: subscribing for real-time updates via some push channel
would be even better for data synchronization. But still after
disconnecting and reconnecting a websocket it would be great to not
having to sync the whole dataset again just to find out what might have
been missed during off-time. Something like *continue/resume* the data
(change event) stream *since* last known state.
Finding out that nothing happened (since) could be a cheap empty http
request/response.
Not sure if I could PR that :/
…On 1/29/21 1:59 PM, wvengen wrote:
@orangeman <https://github.com/orangeman> that makes sense; for
real-time updates I hope someday something with websockets could be
used (so that e.g. when the order is closing soon, members can see
real-time updates when ordering), for offline syncing some standard
parameter (like |since|) could be added to endpoints to only return
records that were modified since that timestamp. I'd welcome PRs for that.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#582 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAGOHMEPEBJQT74BRIZA6TS4KWKDANCNFSM4F6CDDVA>.
|
Hi all! I would like to give the REST API a try. Is it ready to be used? I could not find a documentation site despite of this thread... I just tried /api/v1/navigation on our foodsoft account and it returned an "invalid_token" error, which looked promising ;-) Thanks, Michael PS: I have to mention, so far, I have no experience in REST API usage. I understand how that it works on regular HTTP requests. But, e.g,, from the content in this thread I'm not sure how authentication works. |
Yes, it is ready to be used. Mostly the user-facing part has been implemented, which is used by foodsoft-shop. Yes, this is usable by a recent version of Foodsoft. You have to setup a token from within Foodsoft. This is document in docs/API.md, which also links to the API documentation. |
Great! Many thanks! I will have a look
…----------------------------------------
02.04.2023 21:57:21 wvengen ***@***.***>:
Yes, it is ready to be used. Mostly the user-facing part has been implemented, which is used by foodsoft-shop[https://github.com/foodcoops/foodsoft-shop]. Yes, this is usable by a recent version of Foodsoft. You have to setup a token from within Foodsoft. This is document in docs/API.md[https://github.com/foodcoops/foodsoft/blob/master/doc/API.md], which also links to the API documentation.
I know that financial transactions are also used by an application using the REST API, I think that is the only part that has more 'admin' related things (e.g. not ordering and such as a user, but working with financial transactions from all users).
—
Reply to this email directly, view it on GitHub[#582 (comment)], or unsubscribe[https://github.com/notifications/unsubscribe-auth/AKMPGR43EI5AYLWBRCW6ND3W7HKZ5ANCNFSM4F6CDDVA].
You are receiving this because you commented.[Verfolgungsbild][https://github.com/notifications/beacon/AKMPGR4JPJPWAT5JISKUAK3W7HKZ5A5CNFSM4F6CDDVKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOLEB6CJY.gif]
|
Ok, I got access via Foodsoft API set up from within my Perl script. Now, checking the docs, I see I am missing "some" admin tasks. As I already mentioned above I am currently running a perl script interacting with a foodsoft instance on app.foodcoops.net to sync data with our shop management DB. This is currently done by loading, analyzing and form filling the foodssoft web pages themselves. Tasks are
I would like to switch to an approach, where my script manipulates the data via Foodsofts API. Currently, the API doesn't seam to support any kind of the transactions I would need. That would be, I assume, something like:
Are there any plans to extend the API to support such admin tasks? |
Thank you for listing your findings and needs clearly. |
Ok, I will take a look at the code and put my limited programming knowledge to the test and see what I can achieve. |
:) 👍 |
I added admin/users as a first step in fork branch. This is based upon #969 as suggested ;-). Commit b4348ff Anyone feel free to have a look at it if you find the time. I'm looking forward to any comments/suggestions/whatever since I'm all new to that ruby/rails/rspec/git stuff. Thanks! I will start with order groups implementation meanwhile. |
thats great @SomeMichael ! If you like to we could make a pair session, I could show you some rswag insights and we could talk about your api changes :) |
As talked about in #572, there is a need for a RESTful API which allows access to all relevant models, for both 'member' and 'admin' tasks. Right now the PRs that found their origin in #429 only include access to a member's resources (those relating to its user and ordergroup).
If we ever want to do admin things using the API (the answer would be "yes"), we'll need to be able to work with in an API. This issue is about discussing how this API would look like.
Some important decisions to make are (feel free to add more):
See More or less per resource in #582 (comment) for what we chose for scopes.
The text was updated successfully, but these errors were encountered: