I have a Django web application, which allows users to do stop/start/install_pkg on a remote server over HTTP from UI. Django web app has start / stop / install_pkg functions already implemented which basically creates the appropriate URL and calls the HTTP url with params.
My goal is to use the same internal functions when user does a REST call like the following:
1. https://api/v1/server/<server_name>/start/?api_key=<api_key>¶ms=<params>
2. https://api/v1/server/<server_name>/stop/?api_key=<api_key>¶ms=<params>
3. https://api/v1/server/<server_name>/install_pkg/?api_key=<api_key>¶ms=<params>
And return JSON response to the caller containing remote server response object.
So far I have used Tastypie library to expose read-only access to model data of the Django web app over REST.
Tastypie tutorial on Non ORM resource shows how to interact with non ORM resources by overriding 9 methods of Tastypie. But given my limited knowledge and understanding I am unclear about how to use Tastypie for my case. Am I missing anything here?
To clarify further - Django web app has ORM entry for each of the remote servers in but this information is static info about a particular remote server like (name, ip, domain, ...) since it is created at the time of registering the remote server to Django web app.
The web service call from the Django web app to the remote server fetches the most current state of the remote server like (app_state, pkg_installed_list, ...) and this data is not getting stored anywhere in my Djnago web app. It is rendered as it is in UI.
Thus a GET on Django web app about the remote server essentially returns the static info.
Thanks,
One way is to only keep track of Server resources and just implement start/stop/install_pkg as custom endpoints.
You would implement the Server Resource under Tastypie to have endpoints for each server using regular ORM based resources. That implements standard REST operations on the resource, GET to read the server info, POST to create new ones if you say you have admin user that needs to add another server to administer it with services, PUT/PATCH to update existing servers.
Then you would extend ServerResource to include additional endpoints by:
prepend_urls
to define 3 custom endpoints (start, stop, install_pkg)Another way is to create ServiceResource as a Non ORM Resource which will be in many to many relationship with the Server Resource. This is more tricky but arguably much cleaner design.
Your ServiceResource would have 2 custom endpoints just like in the previous scenario (start/stop) but to install a service on a server you would send a PUT/PATCH to the ServerResource that you want to associate with that service.
For more specific answer please state more specific questions.
See Tastypie cookbook for some solid details on how to proceed:
This search example uses the override_urls
which is what you want to use in 0.9.11 and has similar behavior to prepend_urls
in 0.9.12 which is not released yet. Depending on which version you are, you need to create 3 custom endpoints:
def override_urls(self):
return [
url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/%start%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('start'), name="api_start"),
url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/%stop%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('stop'), name="api_stop"),
url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/%install_pkg%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('install_pkg'), name="api_install_pkg"),
]
Then you need to define the 3 handlers similar to the search example on the ServerResource. I will give you a starting point for the start function. This is an example of a synchronous operation. If you want it to be asynchronous you will need a lot more, but its a starting point.
from tastypie.http import Http
def start(self, request, **kwargs):
self.method_check(request, allowed=['post'])
self.is_authenticated(request)
self.throttle_check(request)
try:
output = function_that_starts_server(kwargs['pk'])
except FailedException as failure:
return self.create_response(request, { 'status' : 'failure', 'reason' : failure }, Http
self.log_throttled_access(request)
return self.create_response(request, { 'status' : 'success', 'log' : output })