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
Actor API Updating #449
Actor API Updating #449
Conversation
The patch API needs to be able to determine the type and id automatically from the request URL and not rely on the user providing that information in the request data. This requires us to know where in the data dictionary to stuff the id once we've derived it. To do this handlers need to be standardized so that common argument names are always the same. This currently includes: - id_ - user The user is important for patch as we don't want someone to be able to pass in a different user. We need to be able to overwrite any user they might try to pass in with the authenticated user making the request.
Common actions are ones that apply to any TLO. Had to change the logic such that if we don't find the action in the TLO's specific actions, we check Common.
I should also note that this doesn't expose every handler for updating everything about an Actor (like campaign, bucket lists, etc.). A lot of those are in core or in another TLO directory so they haven't been added yet. |
}, | ||
} | ||
|
||
path = bundle.request.path[:-1].split('/') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a programmatic way to get the part of the API being accessed instead of string mangling? Valid (though odd) paths such as "crits/api/v1/emails///" would probably cause issues here. Maybe looking at the meta attribute of bundle.obj for its type?
Conflicts: crits/actors/handlers.py crits/actors/views.py
DO NOT ACCEPT THIS YET. For anyone who is up for testing this, I need a hand. Here's the rub: I modified this PR slightly to remove the campaign handler exposure since I didn't actually modify those handlers yet. More importantly, I exposed the "run_service" handler so you can execute services against a TLO through the API. I added 'patch' to all of the TLOs so that this can be used. Here's where stuff goes nuts... I attempted to test this with a PATCH request, both via command-line cURL and with python requests. I was greeted with the following: >>> r = requests.patch(url)
>>> r.text
u'{"error_message": "PATCH",
"traceback": "Traceback (most recent call last):
File "/usr/local/Cellar/python/2.7.8_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tastypie/resources.py", line 201, in wrapper
response = callback(request, *args, **kwargs)
File "/usr/local/Cellar/python/2.7.8_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tastypie/resources.py", line 441, in dispatch_detail
return self.dispatch('detail', request, **kwargs)
File "/usr/local/Cellar/python/2.7.8_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django_tastypie_mongoengine-0.4.5-py2.7.egg/tastypie_mongoengine/resources.py", line 385, in dispatch
assert request.method.lower() not in ('put', 'post', 'patch'), request.method
AssertionError: PATCH"}'
>>> r.request.method.lower()
'patch'
>>> This seemed very odd to me so I went back to If anyone has a chance and can test this branch, please do so and let me know how it goes. I'm still trying to track down this bug. I have a SO question out as well as a comment in a Github issue for django-tastypie-mongoengine. No bites yet. I've tried newer versions of said python library and nothing changes. |
Digging through some old brain cells here from working with this library... If you don't provide a body/data in the request (you didn't in your example) the only valid method is a GET request. All the others expect data to be sent with the request. So you fail the validation check. Update: |
@dsnellgrove that is quite annoying. It winds up working if you pass everything except for the username and api_key as data. I found a code issue after you pointed me in the right direction though, and now you can execute services through the API! :D Thanks! |
If we don't find the key in the actions dict, default to 'Common' and fail if we don't find the action in there.
Using proper django methods, get the resource name and pk to lookup the object instead of parsing strings and hoping for the best.
A bump in the road I hit when experimenting was that tastypie won't authenticate with form parameters for PATCH requests. You have to put the username and api_key in the query string. |
You get a strange error if you don't supply an actor id in the request:
Not really a bug but just something to keep in mind. |
Would you be willing to share the request you are making? Seems odd as it's not hitting any of our code yet in that traceback. |
Sure thing: I've figured out that it happens after a call to On another note, shouldn't line 648 of |
Ahh. If you are doing a PATCH you use the details URL (/api/v1/actors//) not the one for GET or POST. See if that helps at all! |
I can't check at the moment from mobile but line 648 is that the dict for the update actions? If so that's just a key and an internal thing that you shouldn't need to know to use the API. You just need to know the value and we do the lookup. |
@mgoffin right, it's the actions dict. The dict uses the resource name(capitlized with When I change the actions I've been able to use the PATCH api to access Actors after making that code change :) |
Ahh. Got it. If you throw up a PR I can try to test it out when j get some time and get that accepted :) thanks for checking it out! |
Done. No problem. I'd like to write a patch to allow the setting of releasability using the add_releasability handler in core. Is this something I can throw under the 'Common' actions? |
Issue #361 covers setting releasability via the API, but I don't think anyone has done any work towards it yet. |
Yea so my goal is to redo the code base to make it so you can add handlers quickly. Here's the process:
If you want to take a stab go for it :) id love to have help! |
Thanks :) I'll give it a shot. |
I don't think we've decided on order (keeping it as-is for the sake of breaking as little as possible). As long as the new arguments are In the "Roles" branch, I'm doing something similar but the |
This change enables updating Actors through the API.
In order to perform an update, you need to send a PATCH request. The request will go into a core API function from tastypie. The request needs to have an "action" parameter set to the action you want to take. From here there will be a lookup to determine if the action is supported for the TLO you are looking to modify. If so, it will take all of the rest of the parameters provides and pass them directly to the handler which handles that action.
In order to support this, handlers need to be modified in a few ways:
id_
).The reason this needs to be standardized is so we can be 100% accurate in ensuring that a user cannot pass in another ObjectId and make changes, and so we can ensure the user's request works directly on the TLO in question.
user
).The reason this needs to be standardized is so we can be 100% accurate in ensuring that the user modifying the TLO is the same user who is making the request (instead of passing in an analyst or username in the parameters and it being overwritten).
**kwargs
needs to be added to each handler. This ensures any oddball parameters which get passed along (whether from tastypie internals or from the user's request) are dropped on the floor and ignored.As such, the API for what to update and how becomes the docstrings for all of the handlers we enabled PATCH for.
There is also a "Common" action group which are things each TLO can have updated (like bucket list, campaign, etc.). There are some interesting things that can happen here depending on what we expose. For example, there's a handler for deleting a TLO but it would make more sense to use the DELETE request. You can add a relationship as an action but we have an API for that already. So there will need to be some design decisions about what we do and do not restrict from the handler side.