Skip to main content

TaskReview app API

If you wish to customize or improve the TaskReview app, it's helpful to know how its UI and server parts interact.

User flow

Here is a typical user journey through TaskReview app:

  • UI gets list of available tasks from GET /tasks
  • User selects a task
  • UI gets list of available qualifications from GET /qualifications
  • UI pulls all unit-worker id pairs from GET /tasks/{id}/worker-units-ids
    • Due to the need to randomly shuffle units grouped by a worker (to mitigate reviewers bias, etc) we're implementing client-side, not server-side, pagination - client gets full list of all ids, creates a page of unit ids, and then pulls data for those specific units.
  • UI initiates units review by worker:
    • Group units by worker
    • Sort workers by number of their units (fewest units go first)
    • Pick them for review one-by-one
  • And then for each worker:
    • UI pulls units by ids from GET /units?unit_ids=[...]
    • UI sorts units by creation_date and pick them for review one-by-one
      • For each reviewed unit:
        • UI pulls unit details from GET /units/details?unit_ids=[...]
        • UI pulls current stats from GET /stats (for entire task and for worker within the task)
        • UI renders unit's review representation in an iframe
        • User can choose to reject/accept unit, grant/revoke qualification, and block the worker
  • When all units are reviewed, UI redirects user to the "Tasks" page
  • User clicks "Show" button in "Stats" column to see hystograms if a Task has suitable data format for them
  • User clicks "Open" button in "Chars" column to see Grafana dashboard to investigate a Task
  • User clicks "Download" button for a reviewed Task
    • UI pulls Task data from GET /tasks/<task_id>/<n_units>/export-results.json endpoint

API endpoints

These are the API specs enabling TaskReview app UI.


GET /api/tasks

Get all available tasks (to select one for review)

Response:

{
"tasks": [
{
"created_at": <timestamp>,
"has_stats": <bool>,
"id": <int>,
"is_reviewed": <bool>,
"name": <str>,
"unit_all_count": <int>,
"unit_completed_count": <int>,
"unit_finished_count": <int>
},
... // more tasks
]
}

GET /api/tasks/{id}

Get metadata for a task

URL parameters:

  • id - id of a task

Response:

{
"id": <int>,
"name": <str>,
"type": <str>,
"created_at": <timestamp>
}

GET /api/tasks/{id}/export-results

Compose on the server-side a single file with reviewed task results.

URL parameters:

  • id - id of a task

Response:

{
"file_created": <bool>,
}

GET /api/tasks/{id}/{n_units}/export-results.json

Serve a single composed file with reviewed task results.

URL parameters:

  • id - id of a task
  • n_units - amount of units. Needed to clear cached file on server and return a new one

Response: Text file with JSON


GET /api/tasks/{id}/stats-results

Assemble stats with results for a Task.

URL parameters:

  • id - id of a task

Response:

{
"stats": {
<str>: {
<str>: <str> | <int>,
...
},
...
},
"task_id": <str>,
"task_name": <str>,
"workers_count": <int>
}

GET /api/tasks/{id}/timeline

Check if Grafana server is available and redirect or return error.

URL parameters:

  • id - id of a task

Response:

{
"dashboard_url": <str> | null,
"server_is_available": <bool>,
"task_name": <str>,
}

GET /api/tasks/{id}/worker-opinions

Returns all Worker Opinions related to a Task.

URL parameters:

  • id - id of a task

Response:

{
"task_name": <str>,
"worker_opinions": [
{
"data": {
"attachments": [
{
"destination": <str>,
"encoding": <str>,
"fieldname": <str>,
"filename": <str>,
"mimetype": <str>,
"originalname": <str>,
"path": <str>,
"size": <int>
},
... // more attachments
],
"questions": [
{
"answer": <str>,
"id": <str>,
"question": <str>,
"reviewed": <bool>,
"toxicity": <str> | null
},
... // more questions
]
},
"unit_data_folder": <str>,
"unit_id": <str>,
"worker_id": <str>
},
... // more worker opinions
]
}

GET /api/tasks/{id}/worker-units-ids

Get full, unpaginated list of unit IDs within a task (for subsequent client-side grouping by worker_id and GET /task-units pagination)

URL parameters:

  • id - id of a task

Response:

{
"worker_units_ids": [
{
"worker_id": <int>,
"unit_id": <int>,
},
... // more ids
]
}

GET /api/qualifications?{worker_id=}

Get all available qualifications (to select "approve" and "reject" qualifications).

GET parameters:

  • worker_id - id of a worker, whom these qualification were granted to

Response:

{
"qualifications": [
{
"creation_date": <str>,
"description": <str>,
"id": <int>,
"name": <str>,
},
... // more qualifications
]
}

POST /api/qualifications

Create a new qualification.

Request:

{
"description": <str>,
"name": <str>, // Required
}

Response:

{
"creation_date": <str>,
"description": <str>,
"id": <int>,
"name": <str>,
}

GET /api/qualifications/{id}

Get metadata for a qualificaition.

URL parameters:

  • id - id of a qualification

Response:

{
"creation_date": <str>,
"description": <str>,
"id": <int>,
"name": <str>,
}

PATCH /api/qualifications/{id}

Update a qualification.

URL parameters:

  • id - id of a qualification

Request:

{
"description": <str>,
"name": <str>, // Required
}

Response:

{
"creation_date": <str>,
"description": <str>,
"id": <int>,
"name": <str>,
}

DELETE /api/qualifications/{id}

Delete a qualificaition.

URL parameters:

  • id - id of a qualification

Response:

{}

GET /api/qualifications/{id}/details

Get additional data about a qualification.

URL parameters:

  • id - id of a qualification

Response:

{
"granted_qualifications_count": <int>,
}

GET /api/qualifications/{id}/workers?{task_id=}

Get list of all bearers of a qualification.

URL parameters:

  • id - id of a qualification

GET parameters:

  • task_id - id of a task

Response:

{
"workers": [
{
"worker_id": <int>,
"value": <int>,
"worker_review_id": <int>, // latest grant of this qualification
"granted_at": <int>, // maps to `worker_review.creation_date` column
},
... // more qualified workers
]
}

POST /api/qualifications/{id}/workers/{worker_id}/grant

Grant qualification to a worker.

URL parameters:

  • id - id of a qualification
  • worker_id - id of a worker

Request:

{
"unit_ids": [<int>, ...], // Required
"value": <int>,
}

Response:

{}

PATCH /api/qualifications/{id}/workers/{worker_id}/grant

Update value of existing granted qualification.

URL parameters:

  • id - id of a qualification
  • worker_id - id of a worker

Request:

{
"explanation": <str>,
"value": <int>,
}

Response:

{}

POST /api/qualifications/{id}/workers/{worker_id}/revoke

Revoke qualification from a worker.

URL parameters:

  • id - id of a qualification
  • worker_id - id of a worker

Request:

{
"unit_ids": [<int>, ...], // Required
}

Response:

{}

PATCH /api/qualifications/{id}/workers/{worker_id}/revoke

Revoke qualification from a worker (see the difference from POST in the code)

URL parameters:

  • id - id of a qualification
  • worker_id - id of a worker

Response:

{}

GET /api/granted-qualifications?{qualification_id=}&{sort=}

Get list of all granted queslifications

GET parameters:

  • qualification_id - id of a qualification that was granted to a workers
  • sort - field name and order to sort resonse results (e.g. value_current, -value_current)

Response:

{
"granted_qualifications": [
{
"granted_at": <str>,
"qualification_id": <str>,
"qualification_name": <str>,
"units": [
{
"creation_date": <str>,
"task_id": <str>,
"task_name": <str>,
"unit_id": <str>,
"value": <int>,
},
... // more units
],
"value_current": <int>,
"worker_id": <str>,
"worker_name": <str>,
},
... // more granted qualifications
],
}

GET /api/units?{task_id=}&{unit_ids=}&{completed=}

Get workers' results (filtered by task_id and/or unit_ids, etc) - without full details of input/output. At least one filtering parameter must be specified.

GET parameters:

  • task_id - id of a task
  • unit_ids - ids of units
  • completed - show completed units or all (true/false)

Response:

{
"units": [
{
"creation_date": <int>,
"id": <int>,
"is_reviewed": <bool>,
"pay_amount": <int>,
"results": {
"start": ,
"end": ,
"inputs_preview": <json str>, // optional
"outputs_preview": <json str>, // optional
},
"review": {
"bonus": <int>,
"review_note": <str>,
},
"status": <str>,
"task_id": <int>,
"worker_id": <int>,
},
... // more units
]
}

GET /api/units/details?{unit_ids=}

Get full input for specified workers results (units_ids parameter is mandatory).

GET parameters:

  • unit_ids - ids of units (Required)

Response:

{
"units": [
{
"has_task_source_review": <bool>,
"id": <int>,
"inputs": <json object>, // instructions for worker
"metadata": <json object>, // any metadata (e.g. Worker Opinion, Unit Reviews, etc)
"outputs": <json object>, // response from worker
"prepared_inputs": <json object>, // prepared instructions from worker
"unit_data_folder": <str>}, // path to data dir in file system
},
... // more units
]
}

POST /api/units/approve

Approve worker's result.

Request:

{
"unit_ids": [<int>, ...], // Required
"review_note": <str>, // optional
"bonus": <int>, // optional
"send_to_worker": <bool>, // optional
}

Response:

{}

POST /api/units/reject

Reject worker's result.

Request:

{
"unit_ids": [<int>, ...], // Required
"review_note": <str>, // optional
"send_to_worker": <bool>, // optional
}

Response:

{}

POST /api/units/soft-reject

Soft-reject worker's result.

Request:

{
"unit_ids": [<int>, ...], // Required
"review_note": <str>, // optional
"send_to_worker": <bool>, // optional
}

Response:

{}

POST /api/workers/{id}/block

Permanently block a worker.

URL parameters:

  • id - id of a worker

Request:

{
"unit_ids": [<int>, ...], // optional
"review_note": <str>, // Required
}

Response:

{}

POST /api/workers/{id}/qualifications/grant

Grant multiple qualifications to a worker with units.

URL parameters:

  • id - id of a worker

Request:

{
"unit_ids": [<int>, ...], // Required
"qualification_grants": [ // Required
{
"qualification_id": <int>,
"value": <int>,
},
...
],
}

Response:

{}

GET /api/workers/{id}/qualifications

Get list of all granted qualifications for a worker.

URL parameters:

  • id - id of a worker

Response:

{
"granted_qualifications": [
{
"worker_id": <int>,
"qualification_id": <int>,
"value": <int>,
"granted_at": <int>, // maps to `worker_review.creation_date` column
}
],
... // more granted qualifications
}

GET /api/review-stats?{task_id=}&{worker_id=}&{since=}&{limit=}

Get stats of (recent) approvals. Either task_id or worker_id (or both) must be present.

GET parameters:

  • task_id - id of a task (Required)
  • worker_id - id of a worker (Required)
  • since - show stats since date or datetime
  • limit - limit amount or items in results

Response:

{
"stats": {
"total_count": <int>, // within the scope of the filters
"reviewed_count": <int>,
"approved_count": <int>,
"rejected_count": <int>,
"soft_rejected_count": <int>,
},
}

GET /api/units/{unit_id}/static/{filename}

Return static file from data directory for specific unit.

URL parameters:

  • unit_id - id of a unit
  • filename - name of a file, that was uploaded by a worker

Response: File that was uploaded during unit completion by a worker


Error response

Exception are returned by the API in this format:

{
"error": <str>,
}