Private
Public Access
1
0

better API doc

This commit is contained in:
Sander Roosendaal
2020-10-21 08:55:08 +02:00
parent 7297675ce8
commit 82d1418bcb
4 changed files with 481 additions and 112 deletions

View File

@@ -114,6 +114,7 @@ class VirtualRaceSerializer(serializers.ModelSerializer):
fields = (
'id',
'name',
'course',
'registration_closure',
'evaluation_closure',
'start_time',

View File

@@ -147,126 +147,492 @@
<p>The workout summary data and the stroke data are obtained and sent
separately.</p>
<p><em>Challenges</em> are accessed through <a href="/rowers/api/challenges/">/rowers/api/challenges/</a>
and <a href="/rowers/api/challenges/1">/rowers/api/challenges/{id}</a> where {id} is the ID of the challenge. Allowed method
is GET.</p>
<p><em>Entries</em> are accessed through <a href="/rowers/api/entries/">/rowers/api/entries/</a>
and <a href="/rowers/api/entries/1">/rowers/api/entries/{id}</a> where {id} is the ID of the entry.
Allowed methods are GET.</p>
<p><em>Charts</em> are accessed through <a href="/rowers/api/charts/">/rowers/api/charts/</a>
and <a href="/rowers/api/charts/1">/rowers/api/charts/{id}</a> where {id} is the ID of the chart.
Allowed method are GET, DELETE.</p>
<p><em>Courses</em> are accessed through <a href="/rowers/api/geocourses/">/rowers/api/geocourses/</a>
and <a href="/rowers/api/geocourses/1">/rowers/api/geocourses/{id}</a> where {id} is the ID of the Course.
Allowed method are GET.</p>
<p><em>Course Standard Collections</em> are accessed through <a href="/rowers/api/standardcollections/">/rowers/api/standardcollections/</a>
and <a href="/rowers/api/standardcollections/1">/rowers/api/standardcollections/{id}</a> where {id} is the ID of the Standard Collection.
Allowed method are GET.</p>
<p><em>Individual Course Standards</em> are accessed through <a href="/rowers/api/standards/1">/rowers/api/standards/{id}</a> where {id} is the ID of the Course Standard.
Allowed method are GET.</p>
<p><em>Workouts</em> are accessed through <a href="/rowers/api/workouts/">/rowers/api/workouts/</a>
and <a href="/rowers/api/workouts/1">/rowers/api/workouts/{id}</a> where {id} is the ID of the Workout.
Allowed method are GET, POST, DELETE.</p>
<h3>POST stroke data - API</h3>
<p>You can only post stroke data to an existing workout with
workout number {id}. If the workout already has stroke data, you
will get a duplication error. This functionality will be expanded in the
future to enable updating stroke data. Stroke data for workout {id} are
posted to:</p>
<h4>API v1</h4>
<p>
<ul class="contentli">
<li><b>https://{{ request.get_host }}/rowers/api/workouts/{id}/strokedata</b></li>
</ul>
</p>
<p>The payload is application/json data and looks as follows:</p>
<p><pre>
{
"distance": [5,12,19,27,35,43,51,59,67,75,82,90,100],
"power": [112,221,511,673,744,754,754,749,729,729,726,709,707],
"hr": [132,131,131,132,133,136,139,142,145,147,150,152,153],
"pace": [145800,116400,88100,80400,77700,77400,77400,77600,78300,78300,78400,79000,79100],
"spm": [11,41,56,59,55,48,48,48,48,48,48,48,49],
"time": [0,2200,4599,7000,9599,12000,14400,16799,19400,21799,24200,26599,2900],
<p>
In the table below {id} indicates the ID of the item.
<table width="100%" class="shortpadded">
<thead>
<tr>
<th>Item</th><th>Access Points</th><th>Permissions</th><th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Workout</td>
<td><a href="/rowers/api/workouts/">/rowers/api/workouts/</a>
<br>
<a href="/rowers/api/workouts/1">/rowers/api/workouts/{id}</a></td>
<td>GET, POST, DELETE</td>
<td>
<pre>{
"id": 18,
"name": "2x",
"date": "2020-10-15",
"workouttype": "water",
"starttime": "08:40:50",
"distance": 9751,
"duration": "00:52:40",
"averagehr": 104,
"maxhr": 122,
"notes": "",
"summary": "Workout Summary - media/97ec07a851-20201015-192157-95763ffd-fd4e-4b5f-bf5f-8a8495c16639.csv\n--|Total|-Total----|--Avg--|-Avg-|Avg-|-Avg-|-Max-|-Avg\n--|Dist-|-Time-----|-Pace--|-Pwr-|SPM-|-HR--|-HR--|-DPS\n--|09751|00:52:40.0|02:42.0|173.0|18.0|104.4|122.0|10.3\nW-|09751|00:52:40.0|02:42.0|173.0|18.0|104.4|122.0|10.3\nR-|00000|00:00:00.0|00:00.0|000.0|00.0|000.0|122.0|00.0\nWorkout Details\n#-|SDist|-Split-|-SPace-|-Pwr-|SPM-|AvgHR|MaxHR|DPS-\n00|09751|52:40.0|02:42.0|173.0|18.0|104.4|122.0|10.3\n",
"boattype": "2x",
"timezone": "Europe/Amsterdam",
"forceunit": "N",
"inboard": 0.88,
"oarlength": 2.89,
"privacy": "visible",
"rankingpiece": false
}
</pre></p>
</pre>
</td>
<h4>API v2</h4>
</tr>
<tr>
<td>Favorite Chart</td>
<td><a href="/rowers/api/charts/">/rowers/api/charts/</a>
<br>
<a href="/rowers/api/charts/1">/rowers/api/charts/{id}</a></td>
<td>GET, DELETE</td>
<td>
<pre>{
"id": 7,
"xparam": "time",
"yparam1": "hr",
"yparam2": "power",
"plottype": "line",
"workouttype": "otw",
"reststrokes": true,
"user": 1
}
</pre>
</td>
<p>
<ul class="contentli">
<li><b>https://{{ request.get_host }}/rowers/api/v2/workouts/{id}/strokedata</b></li>
</ul>
</p>
</tr>
<tr>
<td>Challenge</td>
<td><a href="/rowers/api/challenges/">/rowers/api/challenges/</a>
<br>
<a href="/rowers/api/challenges/1">/rowers/api/challenges/{id}</a></td>
<td>GET</td>
<td>
<pre>
{
"id": 1,
"name": "Alphen",
"course": 1,
"registration_closure": "2020-10-18T08:45:00+02:00",
"evaluation_closure": "2020-10-18T12:16:00+02:00",
"start_time": "08:45:00",
"end_time": "12:00:00",
"country": "Nederland",
"timezone": "Europe/Amsterdam",
"contact_phone": "",
"contact_email": "",
"entries": [
{
"id": 1,
"username": "Sander Roosendaal",
"teamname": null,
"boattype": "1x",
"sex": "male",
"age": 48,
"adaptiveclass": "None",
"skillclass": "Open",
"coursecompleted": false,
"distance": 0,
"duration": "00:00:00",
"points": 0.0,
"entrycategory": null
}
],
"coursestandards": null
}
</pre>
</td>
<p>The payload is application/json data and looks as follows:</p>
</tr>
<tr>
<td>Challenge Entry</td>
<td><a href="/rowers/api/entries/">/rowers/api/entries/</a>
<br>
<a href="/rowers/api/entries/1">/rowers/api/entries/{id}</a></td>
<td>GET, POST</td>
<td>
<pre>{
"id": 1,
"teamname": null,
"adaptiveclass": "None",
"skillclass": "Open",
"race": {
"id": 1,
"name": "Alphen",
"course": 1,
"registration_closure": "2020-10-18T08:45:00+02:00",
"evaluation_closure": "2020-10-18T12:16:00+02:00",
"start_time": "08:45:00",
"end_time": "12:00:00",
"country": "Nederland",
"timezone": "Europe/Amsterdam",
"contact_phone": "",
"contact_email": "",
"entries": [
{
"id": 1,
"username": "Sander Roosendaal",
"teamname": null,
"boattype": "1x",
"sex": "male",
"age": 48,
"adaptiveclass": "None",
"skillclass": "Open",
"coursecompleted": false,
"distance": 0,
"duration": "00:00:00",
"points": 0.0,
"entrycategory": null
}
],
"coursestandards": null
},
"distance": 0,
"duration": "00:00:00",
"points": 0.0,
"boattype": "1x",
"sex": "male",
"age": 48,
"entrycategory": null
}
</pre>
</td>
<p><pre>
{"data":
[
{"distance":5, "power": 112, "hr": 132, "pace": 145800, "spm": 11, "time": 0},
{"distance":12, "power": 221, "hr": 131, "pace": 116400, "spm": 41, "time": 2200},
{"distance":19, "power": 511, "hr": 131, "pace": 88100, "spm": 56, "time": 4599},
{"distance":27, "power": 673, "hr": 132, "pace": 80400, "spm": 59, "time": 7000},
{"distance":35, "power": 744, "hr": 133, "pace": 77700, "spm": 55, "time": 9599},
{"distance":43, "power": 754, "hr": 136, "pace": 77400, "spm": 48, "time": 12000},
{"distance":51, "power": 754, "hr": 139, "pace": 77400, "spm": 48, "time": 14400},
{"distance":59, "power": 749, "hr": 142, "pace": 77600, "spm": 48, "time": 16799},
{"distance":67, "power": 729, "hr": 145, "pace": 78300, "spm": 48, "time": 19400},
{"distance":75, "power": 729, "hr": 147, "pace": 78300, "spm": 48, "time": 21799},
{"distance":82, "power": 726, "hr": 150, "pace": 78400, "spm": 48, "time": 24200},
{"distance":90, "power": 709, "hr": 152, "pace": 79000, "spm": 48, "time": 26599},
{"distance":100, "power": 707, "hr": 153, "pace": 79100, "spm": 49, "time": 29000},
</tr>
<tr>
<td>Course</td>
<td><a href="/rowers/api/geocourses/">/rowers/api/geocourses/</a>
<br>
<a href="/rowers/api/geocourses/1">/rowers/api/geocourses/{id}</a></td>
<td>GET</td>
<td>
Example shortened for brevity (omitted gates 2-14):
<pre>
{
"id": 1,
"name": "Alphen - Alphen aan den Rijn",
"distance": 14847,
"country": "Nederland",
"notes": "\n\n",
"polygons": [
{
"id": 1,
"name": "Start",
"order_in_course": 0,
"points": [
{
"id": 1,
"latitude": 52.14611068342334,
"longitude": 4.704149601313898,
"order_in_poly": 0
},
{
"id": 2,
"latitude": 52.14606840788696,
"longitude": 4.704648516706039,
"order_in_poly": 1
},
{
"id": 3,
"latitude": 52.14626893773362,
"longitude": 4.704642182077736,
"order_in_poly": 2
},
{
"id": 4,
"latitude": 52.14628828501986,
"longitude": 4.704151599747837,
"order_in_poly": 3
},
{
"id": 5,
"latitude": 52.14611068342334,
"longitude": 4.704149601313898,
"order_in_poly": 4
}
]
},
{
"id": 15,
"name": "Finish",
"order_in_course": 14,
"points": [
{
"id": 71,
"latitude": 52.1461319705247,
"longitude": 4.70414987291546,
"order_in_poly": 0
},
{
"id": 72,
"latitude": 52.14607111930849,
"longitude": 4.704561170436561,
"order_in_poly": 1
},
{
"id": 73,
"latitude": 52.14626893773362,
"longitude": 4.704642182077736,
"order_in_poly": 2
},
{
"id": 74,
"latitude": 52.14628831020436,
"longitude": 4.70415735390207,
"order_in_poly": 3
},
{
"id": 75,
"latitude": 52.1461319705247,
"longitude": 4.70414987291546,
"order_in_poly": 4
}
]
}
]
}
</pre></p>
</pre>
</td>
<p>For both v1 and v2, mandatory data fields are:</p>
<p>
<ul class="contentli">
<li><b>time</b>: Time (milliseconds since workout start)</li>
<li><b>distance</b>: Distance (meters)</li>
<li><b>pace</b>: Pace (milliseconds per 500m)</li>
<li><b>spm</b> Stroke rate (strokes per minute)</li>
</ul>
</tr>
<tr>
<td>Course Time Standard Collection</td>
<td><a href="/rowers/api/standardcollections/">/rowers/api/standardcollections/</a>
<br>
<a href="/rowers/api/standardcollections/1">/rowers/api/standarcollections/{id}</a></td>
<td>GET</td>
<td>
Example shortened for brevity (showing only first three):
<pre>{
"id": 1,
"name": "Charles River Times Standards",
"notes": "",
"active": true,
"standards": [
{
"id": 1,
"name": "M1x",
"coursedistance": 4700,
"coursetime": "17:15.0",
"agemin": 0,
"agemax": 120,
"boatclass": "water",
"boattype": "1x",
"sex": "male",
"weightclass": "hwt",
"adaptiveclass": "None",
"skillclass": "Open",
"standardcollection": 1
},
{
"id": 2,
"name": "MLW1x",
"coursedistance": 4700,
"coursetime": "17:15.0",
"agemin": 0,
"agemax": 120,
"boatclass": "water",
"boattype": "1x",
"sex": "male",
"weightclass": "lwt",
"adaptiveclass": "None",
"skillclass": "Open",
"standardcollection": 1
},
{
"id": 3,
"name": "MYouth1x",
"coursedistance": 4700,
"coursetime": "18:30.0",
"agemin": 15,
"agemax": 18,
"boatclass": "water",
"boattype": "1x",
"sex": "male",
"weightclass": "hwt",
"adaptiveclass": "None",
"skillclass": "Open",
"standardcollection": 1
},
]
}
</pre>
</td>
</tr>
<tr>
<td>Individual Course Time Standard</td>
<td><a href="/rowers/api/standards/">/rowers/api/standards/</a>
<br>
<a href="/rowers/api/standards/1">/rowers/api/standards/{id}</a></td>
<td>GET, POST
<td>
<pre>{
"id": 1,
"name": "M1x",
"coursedistance": 4700,
"coursetime": "17:15.0",
"agemin": 0,
"agemax": 120,
"boatclass": "water",
"boattype": "1x",
"sex": "male",
"weightclass": "hwt",
"adaptiveclass": "None",
"skillclass": "Open",
"standardcollection": 1
}
</pre>
</td>
</tr>
<tr>
<td>Stroke Data (v1)</td>
<td><a href="/rowers/api/workouts/1/strokedata">/rowers/api/workouts/{id}/strokedata</a>
</td>
<td>GET, POST</td>
<td>
<pre>{
"distance": [23, 46, 48],
"time": [3200, 6700, 10099],
"spm": [16.4, 21.2, 19.8],
"pace": [155068, 144402, 138830],
"power": [84,6, 117.2, 141.3],
"hr": [85, 91, 95]
}
</pre>
You can only post stroke data to an existing workout with
workout number {id}. If the workout already has stroke data, you
will get a duplication error. This functionality will be expanded in the
future to enable updating stroke data.
<br>
<p>For both v1 and v2, mandatory data fields are:</p>
<p>
<ul class="contentli">
<li><b>time</b>: Time (milliseconds since workout start)</li>
<li><b>distance</b>: Distance (meters)</li>
<li><b>pace</b>: Pace (milliseconds per 500m)</li>
<li><b>spm</b> Stroke rate (strokes per minute)</li>
</ul>
</p>
<p>Optional data fiels are:</p>
<p>
<ul class="contentli">
<li><b>power</b>: Power (Watt)</li>
<li><b>latitude</b>: GPS position (latitude)</li>
<li><b>longitude</b>: GPS position (longitude)</li>
<li><b>drivelength</b>: Drive length (meters)</li>
<li><b>dragfactor</b>: Drag factor</li>
<li><b>drivetime</b>: Drive time (ms)</li>
<li><b>strokerecoverytime</b>: Recovery time (ms)</li>
<li><b>averagedriveforce</b>: Average handle force (lbs)</li>
<li><b>peakdriveforce</b>: Peak handle force (lbs)</li>
<li><b>lapidx</b>: Lap identifier</li>
<li><b>hr</b>: Heart rate (beats per minute)</li>
<li><b>wash</b>: Wash as defined per Empower oarlock (degrees)</li>
<li><b>catch</b>: Catch angle per Empower oarlock (degrees)</li>
<li><b>finish</b>: Finish angle per Empower oarlock (degrees)</li>
<li><b>peakforceangle</b>: Peak Force Angle per Empower oarlock (degrees)</li>
<li><b>slip</b>: Slip as defined per Empower oarlock (degrees)</li>
</ul>
</p>
<p>For both API versions, consistency checks will be done and the stroke data will be
refused if the mandatory data fields don't pass the checks.
All mandatory data fields
must have the same number of records. If an optional data field
fails a test, its values are silently replaced by zeros.</p>
</td>
</tr>
<tr>
<td>Stroke Data (v2)</td>
<td><a href="/rowers/api/v2/workouts/1/strokedata">/rowers/api/v2/workouts/{id}/strokedata</a>
</td>
<td>GET, POST</td>
<td>
<pre>[
"data": [
{
"time": 3200.0000476837,
"pace": 155068.4885951763,
"hr": 85.7857142857,
"power": 84.6531131591,
"distance": 23,
"spm": 16.380952381
},
{
"time": 6700.0000476837,
"pace" : 144402.6407586741,
"hr": 91.2142857143,
"power": 117.458827834,
"distance": 36,
"spm": 21.1666666667
},
{
"time": 10099.9999046326,
"pace": 138830.8712654931,
"hr": 95.7142857143,
"power": 141.31057207,
"distance": 48,
"spm": 19.8095238095
}
]
]
</pre>
You can only post stroke data to an existing workout with
workout number {id}. If the workout already has stroke data, you
will get a duplication error. This functionality will be expanded in the
future to enable updating stroke data.
<br>
<p>For both v1 and v2, mandatory data fields are:</p>
<p>
<ul class="contentli">
<li><b>time</b>: Time (milliseconds since workout start)</li>
<li><b>distance</b>: Distance (meters)</li>
<li><b>pace</b>: Pace (milliseconds per 500m)</li>
<li><b>spm</b> Stroke rate (strokes per minute)</li>
</ul>
</p>
<p>Optional data fiels are:</p>
<p>
<ul class="contentli">
<li><b>power</b>: Power (Watt)</li>
<li><b>latitude</b>: GPS position (latitude)</li>
<li><b>longitude</b>: GPS position (longitude)</li>
<li><b>drivelength</b>: Drive length (meters)</li>
<li><b>dragfactor</b>: Drag factor</li>
<li><b>drivetime</b>: Drive time (ms)</li>
<li><b>strokerecoverytime</b>: Recovery time (ms)</li>
<li><b>averagedriveforce</b>: Average handle force (lbs)</li>
<li><b>peakdriveforce</b>: Peak handle force (lbs)</li>
<li><b>lapidx</b>: Lap identifier</li>
<li><b>hr</b>: Heart rate (beats per minute)</li>
<li><b>wash</b>: Wash as defined per Empower oarlock (degrees)</li>
<li><b>catch</b>: Catch angle per Empower oarlock (degrees)</li>
<li><b>finish</b>: Finish angle per Empower oarlock (degrees)</li>
<li><b>peakforceangle</b>: Peak Force Angle per Empower oarlock (degrees)</li>
<li><b>slip</b>: Slip as defined per Empower oarlock (degrees)</li>
</ul>
</p>
<p>For both API versions, consistency checks will be done and the stroke data will be
refused if the mandatory data fields don't pass the checks.
All mandatory data fields
must have the same number of records. If an optional data field
fails a test, its values are silently replaced by zeros.</p>
</td>
</tr>
</tbody>
</table>
</p>
<p>Optional data fiels are:</p>
<p>
<ul class="contentli">
<li><b>power</b>: Power (Watt)</li>
<li><b>latitude</b>: GPS position (latitude)</li>
<li><b>longitude</b>: GPS position (longitude)</li>
<li><b>drivelength</b>: Drive length (meters)</li>
<li><b>dragfactor</b>: Drag factor</li>
<li><b>drivetime</b>: Drive time (ms)</li>
<li><b>strokerecoverytime</b>: Recovery time (ms)</li>
<li><b>averagedriveforce</b>: Average handle force (lbs)</li>
<li><b>peakdriveforce</b>: Peak handle force (lbs)</li>
<li><b>lapidx</b>: Lap identifier</li>
<li><b>hr</b>: Heart rate (beats per minute)</li>
<li><b>wash</b>: Wash as defined per Empower oarlock (degrees)</li>
<li><b>catch</b>: Catch angle per Empower oarlock (degrees)</li>
<li><b>finish</b>: Finish angle per Empower oarlock (degrees)</li>
<li><b>peakforceangle</b>: Peak Force Angle per Empower oarlock (degrees)</li>
<li><b>slip</b>: Slip as defined per Empower oarlock (degrees)</li>
</ul>
</p>
<p>For both API versions, consistency checks will be done and the stroke data will be
refused if the mandatory data fields don't pass the checks.
All mandatory data fields
must have the same number of records. If an optional data field
fails a test, its values are silently replaced by zeros.</p>
</li>
</ul>

View File

@@ -115,7 +115,7 @@ class EntryViewSet(viewsets.ModelViewSet):
except TypeError:
return []
http_method_names = ['get']
http_method_names = ['get','post']
permission_classes = (
IsCompetitorOrNot,

View File

@@ -107,8 +107,10 @@ def strokedatajson_v2(request,id):
logfile.write(request.user.username+"(GET) \n")
data = datadf.to_json(orient='records')
data2 = json.loads(data)
data2 = {"data":data2}
return JSONResponse(data)
return JSONResponse(data2)
if request.method == 'POST':
with open('media/apilog.log','a') as logfile: