Skip to content
Snippets Groups Projects
Commit bba73fe1 authored by Ryan Sanford's avatar Ryan Sanford
Browse files

Add documentation examples for REST

parent d3b1b2bd
No related branches found
No related tags found
No related merge requests found
......@@ -25,9 +25,79 @@ log = config.log
class Config(base.RequestHandler):
def get(self):
"""
.. http:get:: /api/config
Return public Scitran configuration information.
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api/config HTTP/1.1
Host: demo.flywheel.io
Accept: */*
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: application/json; charset=utf-8
{"site": {"central_url": "https://sdmc.scitran.io/api", "ssl_cert": null, "api_url": "https://10.240.0.2:443/api", "registered": false, "id": "local", "name": "BaliDemo"}, "modified": "2016-03-31T16:30:00.852000+00:00", "auth": {"id_endpoint": "https://www.googleapis.com/plus/v1/people/me/openIdConnect", "verify_endpoint": "https://www.googleapis.com/oauth2/v1/tokeninfo", "client_id": "949263322061-6q4fqi0m4ihkp1v5n6v8q9bef4gd0f1k.apps.googleusercontent.com", "auth_endpoint": "https://accounts.google.com/o/oauth2/auth"}, "created": "2016-03-31T16:30:00.852000+00:00"}
"""
return config.get_public_config()
def get_js(self):
"""
.. http:get:: /api/config.js
Return public Scitran configuration information in javascript format.
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api/config.js HTTP/1.1
Host: demo.flywheel.io
Accept: */*
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
config = {
"auth": {
"auth_endpoint": "https://accounts.google.com/o/oauth2/auth",
"client_id": "949263322061-6q4fqi0m4ihkp1v5n6v8q9bef4gd0f1k.apps.googleusercontent.com",
"id_endpoint": "https://www.googleapis.com/plus/v1/people/me/openIdConnect",
"verify_endpoint": "https://www.googleapis.com/oauth2/v1/tokeninfo"
},
"created": "2016-03-31T16:30:00.852000+00:00",
"modified": "2016-03-31T16:30:00.852000+00:00",
"site": {
"api_url": "https://10.240.0.2:443/api",
"central_url": "https://sdmc.scitran.io/api",
"id": "local",
"name": "BaliDemo",
"registered": false,
"ssl_cert": null
}
"""
self.response.write(
'config = ' +
json.dumps( self.get(), sort_keys=True, indent=4, separators=(',', ': '), default=util.custom_json_serializer,) +
......@@ -37,6 +107,33 @@ class Config(base.RequestHandler):
class Version(base.RequestHandler):
def get(self):
"""
.. http:get:: /api/version
Return database schema in javascript format.
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api/version HTTP/1.1
Host: demo.flywheel.io
Accept: */*
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: application/json; charset=utf-8
{"_id": "version", "database": 2}
"""
return config.get_version()
#regexes used in routing table:
......
......@@ -89,7 +89,34 @@ def clean_remotes(db, site_id):
class CentralClient(base.RequestHandler):
def sites(self):
"""Return local and remote sites."""
"""
.. http:get:: /api/sites
Return local and remote sites.
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api/sites HTTP/1.1
Host: demo.flywheel.io
Accept: */*
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: application/json; charset=utf-8
[{"onload": true, "_id": "local", "name": "BaliDemo"}]
"""
projection = ['name', 'onload']
# TODO onload for local is true
site_id = config.get_item('site', 'id')
......@@ -107,6 +134,14 @@ class CentralClient(base.RequestHandler):
return sites
def register(self):
"""
.. http:post:: /api/register
NOT IMPLEMENTED -- Return local and remote sites.
:statuscode 404: Not Implemented
"""
self.abort(404, 'register endpoint is not implemented')
# FIXME the code below should be properly ported using the new config
# every request to this route is aborted at the moment
......
......@@ -153,6 +153,24 @@ class Download(base.RequestHandler):
stream.close()
def download(self):
"""
.. http:get:: /api/download
Download GET Description...
:statuscode 400: describe me
:statuscode 404: describe me
.. http:post:: /api/download
Download POST Description...
:statuscode 400: describe me
:statuscode 404: describe me
"""
"""
In downloads we use filters in the payload to exclude/include files.
To pass a single filter, each of its conditions should be satisfied.
......
......@@ -352,6 +352,45 @@ class FileListHandler(ListHandler):
return ticket
def get(self, cont_name, list_name, **kwargs):
"""
.. http:get:: /api/(cont_name)/(cid)/files/(file_name)
Gets the ticket used to download the file when the ticket is not provided.
Downloads the file when the ticket is provided.
:query ticket: should be empty
:param cont_name: one of ``projects``, ``sessions``, ``acquisitions``, ``collections``
:type cont_name: string
:param cid: Container ID
:type cid: string
:statuscode 200: no error
:statuscode 400: explain...
:statuscode 409: explain...
**Example request**:
.. sourcecode:: http
GET /api/acquisitions/57081d06b386a6dc79ca383c/files/fMRI%20Loc%20Word%20Face%20Obj.zip?ticket= HTTP/1.1
Host: demo.flywheel.io
Accept: */*
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: application/json; charset=utf-8
{"ticket": "1e975e3d-21e9-41f4-bb97-261f03d35ba1"}
"""
log.error('{} {} {}'.format(cont_name, list_name, kwargs))
_id = kwargs.pop('cid')
container, permchecker, storage, _, _, keycheck = self._initialize_request(cont_name, list_name, _id)
......
......@@ -60,6 +60,39 @@ class UserHandler(base.RequestHandler):
return result
def put(self, _id):
"""
.. http:put:: /api/users/(uid)
Update user
:query root: explain...
:param uid: User ID (email address)
:type uid: string
:reqheader Authorization: required OAuth session token
**Example request**:
.. sourcecode:: http
PUT /api/users/jdoe@gmail.com?root=true HTTP/1.1
Host: demo.flywheel.io
Authorization: ya29..a356DasssSFG_FEbggasr435g54GG$33DFGSssghnj-HSsdfgs450nvsASAPinZCXVqertt
Content-Type: application/json;charset=UTF-8
{"firstname":"John","lastname":"Doe","email":"jdoe@gmail.com","root":true}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 15
{"modified": 1}
"""
self._init_storage()
user = self._get_user(_id)
permchecker = userauth.default(self, user)
......@@ -77,6 +110,35 @@ class UserHandler(base.RequestHandler):
self.abort(404, 'User {} not updated'.format(_id))
def post(self):
"""
.. http:post:: /api/users
Add user
:query root: explain...
:reqheader Authorization: required OAuth session token
**Example request**:
.. sourcecode:: http
POST /api/users?root=true HTTP/1.1
Host: demo.flywheel.io
Authorization: ya29..a356DasssSFG_FEbggasr435g54GG$33DFGSssghnj-HSsdfgs450nvsASAPinZCXVqertt
Content-Type: application/json;charset=UTF-8
{"_id":"jane.doe@gmail.com","firstname":"Jane","lastname":"Doe","email":"jane.doe@gmail.com"}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
{"_id": "jane.doe@gmail.com"}
"""
self._init_storage()
permchecker = userauth.default(self)
payload = self.request.json_body
......@@ -153,4 +215,3 @@ class UserHandler(base.RequestHandler):
return user
else:
self.abort(404, 'user {} not found'.format(_id))
......@@ -9,11 +9,208 @@ log = config.log
class Root(base.RequestHandler):
def head(self):
"""Return 200 OK."""
"""
.. http:head:: /api
Confirm endpoint is ready for requests
:statuscode 200: no error
"""
pass
def get(self):
"""Return API documentation"""
"""
.. http:get:: /api
Return API documentation
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api HTTP/1.1
Host: demo.flywheel.io
Accept: text/html
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: text/html
<html>
<head>
<title>SciTran API</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<style type="text/css">
table {width:0%; border-width:1px; padding: 0;border-collapse: collapse;}
table tr {border-top: 1px solid #b8b8b8; background-color: white; margin: 0; padding: 0;}
table tr:nth-child(2n) {background-color: #f8f8f8;}
table thead tr :last-child {width:100%;}
table tr th {font-weight: bold; border: 1px solid #b8b8b8; background-color: #cdcdcd; margin: 0; padding: 6px 13px;}
table tr th {font-weight: bold; border: 1px solid #b8b8b8; background-color: #cdcdcd; margin: 0; padding: 6px 13px;}
table tr td {border: 1px solid #b8b8b8; margin: 0; padding: 6px 13px;}
table tr th :first-child, table tr td :first-child {margin-top: 0;}
table tr th :last-child, table tr td :last-child {margin-bottom: 0;}
</style>
</head>
<body style="min-width:900px">
<form name="username" action="" method="get">
Username: <input type="text" name="user">
Root: <input type="checkbox" name="root" value="1">
<input type="submit" value="Generate Custom Links">
</form>
<table>
<thead>
<tr>
<th align="left">Resource</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><a href="/api/sites">/sites</a></td>
<td align="left">local and remote sites</td>
</tr>
<tr>
<td align="left">/download</td>
<td align="left">download</td>
</tr>
<tr>
<td align="left"><a href="/api/users">/users</a></td>
<td align="left">list of users</td>
</tr>
<tr>
<td align="left"><a href="/api/users/self">/users/self</a></td>
<td align="left">user identity</td>
</tr>
<tr>
<td align="left"><a href="/api/users/roles">/users/roles</a></td>
<td align="left">user roles</td>
</tr>
<tr>
<td align="left"><a href="/api/users/*&amp;lt;uid&amp;gt;*">/users/<em>&lt;uid&gt;</em></a></td>
<td align="left">details for user <em>&lt;uid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/users/*&amp;lt;uid&amp;gt;*/groups">/users/<em>&lt;uid&gt;</em>/groups</a></td>
<td align="left">groups for user <em>&lt;uid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/users/*&amp;lt;uid&amp;gt;*/projects">/users/<em>&lt;uid&gt;</em>/projects</a></td>
<td align="left">projects for user <em>&lt;uid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/groups">/groups</a></td>
<td align="left">list of groups</td>
</tr>
<tr>
<td align="left">/groups/<em>&lt;gid&gt;</em></td>
<td align="left">details for group <em>&lt;gid&gt;</em></td>
</tr>
<tr>
<td align="left">/groups/<em>&lt;gid&gt;</em>/projects</td>
<td align="left">list of projects for group <em>&lt;gid&gt;</em></td>
</tr>
<tr>
<td align="left">/groups/<em>&lt;gid&gt;</em>/sessions</td>
<td align="left">list of sessions for group <em>&lt;gid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/projects">/projects</a></td>
<td align="left">list of projects</td>
</tr>
<tr>
<td align="left"><a href="/api/projects/groups">/projects/groups</a></td>
<td align="left">groups for projects</td>
</tr>
<tr>
<td align="left"><a href="/api/projects/schema">/projects/schema</a></td>
<td align="left">schema for single project</td>
</tr>
<tr>
<td align="left">/projects/<em>&lt;pid&gt;</em></td>
<td align="left">details for project <em>&lt;pid&gt;</em></td>
</tr>
<tr>
<td align="left">/projects/<em>&lt;pid&gt;</em>/sessions</td>
<td align="left">list sessions for project <em>&lt;pid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/sessions">/sessions</a></td>
<td align="left">list of sessions</td>
</tr>
<tr>
<td align="left"><a href="/api/sessions/schema">/sessions/schema</a></td>
<td align="left">schema for single session</td>
</tr>
<tr>
<td align="left">/sessions/<em>&lt;sid&gt;</em></td>
<td align="left">details for session <em>&lt;sid&gt;</em></td>
</tr>
<tr>
<td align="left">/sessions/<em>&lt;sid&gt;</em>/move</td>
<td align="left">move session <em>&lt;sid&gt;</em> to a different project</td>
</tr>
<tr>
<td align="left">/sessions/<em>&lt;sid&gt;</em>/acquisitions</td>
<td align="left">list acquisitions for session <em>&lt;sid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/acquisitions/schema">/acquisitions/schema</a></td>
<td align="left">schema for single acquisition</td>
</tr>
<tr>
<td align="left">/acquisitions/<em>&lt;aid&gt;</em></td>
<td align="left">details for acquisition <em>&lt;aid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/collections">/collections</a></td>
<td align="left">list of collections</td>
</tr>
<tr>
<td align="left"><a href="/api/collections/schema">/collections/schema</a></td>
<td align="left">schema for single collection</td>
</tr>
<tr>
<td align="left">/collections/<em>&lt;cid&gt;</em></td>
<td align="left">details for collection <em>&lt;cid&gt;</em></td>
</tr>
<tr>
<td align="left">/collections/<em>&lt;cid&gt;</em>/sessions</td>
<td align="left">list of sessions for collection <em>&lt;cid&gt;</em></td>
</tr>
<tr>
<td align="left">/collections/<em>&lt;cid&gt;</em>/acquisitions</td>
<td align="left">list of acquisitions for collection <em>&lt;cid&gt;</em></td>
</tr>
<tr>
<td align="left"><a href="/api/schema/group">/schema/group</a></td>
<td align="left">group schema</td>
</tr>
<tr>
<td align="left"><a href="/api/schema/user">/schema/user</a></td>
<td align="left">user schema</td>
</tr>
</tbody>
</table></body>
</html>
:query sort: one of ``hit``, ``created-at``
:query offset: offset number. default is 0
:query limit: limit number. default is 30
:reqheader Accept: the response content type depends on
:mailheader:`Accept` header
:reqheader Authorization: optional OAuth token to authenticate
:resheader Content-Type: this depends on :mailheader:`Accept`
header of request
"""
resources = """
Resource | Description
:-----------------------------------|:-----------------------
......
......@@ -176,7 +176,15 @@ class Upload(base.RequestHandler):
log.info('Received %s [%s, %s/s] from %s' % (file_store.filename, util.hrsize(file_store.size), util.hrsize(throughput), self.request.client_addr))
def upload(self, strategy):
"""Receive a sortable reaper upload."""
"""
.. http:post:: /api/upload/<strategy:label|uid>
Receive a sortable reaper upload.
:statuscode 402: no error
:statuscode 500: no error
"""
if not self.superuser_request:
self.abort(402, 'uploads must be from an authorized drone')
......@@ -191,7 +199,17 @@ class Upload(base.RequestHandler):
def engine(self):
"""
URL format: api/engine?level=<container_type>&id=<container_id>&job=<job_id>
.. http:post:: /api/engine
Confirm endpoint is ready for requests
:query level: container_type
:query id: container_id
:query job: job_id
:statuscode 400: describe me
:statuscode 402: describe me
:statuscode 404: describe me
"""
if not self.superuser_request:
......@@ -268,8 +286,14 @@ class Upload(base.RequestHandler):
def clean_packfile_tokens(self):
"""
Clean up expired upload tokens and invalid token directories.
.. http:post:: /api/clean-packfiles
Clean up expired upload tokens and invalid token directories.
:statuscode 402: describe me
"""
"""
Ref placer.TokenPlacer and FileListHandler.packfile_start for context.
"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment