This API implementation offers all the required functionality to support specified features and data access capabilities.
Endpoint is a term that means an URI that implements some functionality.
URI parameters are baked into the resource path. For example; /api/company/123/order/90121
has two URI parameters. The ID of the company entity (123
) and the ID of the order (90121
).
Query parameters are appended to the URI with ?
character and chained with &
separator. For example; /api/classifieddata?begin=1541409470&fields=ss00p01,ss00p02
has two query parameters; begin
, which is an UNIT timestamp in string format and fields
, which is a string that can be converted into a comma separated list.
Payload parameters are located in the HTTP payload (body) portion, in a JSON format (as far as this API specification is concerned). Usage of client-side payload parameters is reserved to data altering actions, such as PUT, PATCH and POST, which need to deliver number of entity attributes. Notable exception is the DELETE HTTP method, which does not need to send entity data and identifies the target for the delete operation through URI parameter (for example; /api/item/028121/delete
). Should the endpoint handle parameters other than entity attributes, they should be included in the Query parameters.
Header parameters are located in the HTTP header. Aside from path/endpoint, HTTP method and response codes, these parameters have no other putpose in this API specification and are left for HTTP and application purposes (such as session management, XSS prevention and access control mechanisms).
Idempotence is a property of an operation, which means that the operation can be applied multiple times (on the same target/entity) and the result will always be identical to the first result. For example; paint_green(X) would make X green. Calling the function any number of times will always result in green X. Thus, the function is idempotent.
An Entity Identifying Endpoint is simply URI that contains the entity ID as a URI Parameter, for example: /api/file/3201
, which gives access to file by ID = 3201.
A Generic Endpoint does not contain entity ID. For example; /api/file
.
Identifying endpoints are used when actions are targeting specified entity and generi endpoints when the identity is either not relevant (search) or not available (create new entity, for example).
Most CRUD (Create, Read, Update, Delete) actions deal with identified entities (/api/entity/<int:id>
), except POST ("create") action. Only the service can give the new entity instance a valid and non-conflicting ID.
A GET Request ("read") action can access either identified entity (making it "fetch" type), or to entity generic (making it a "search" request).
Idiotic teachings in almost all universities, in their database courses, tell us to use "some immutable attribute of the entity as a primary key". This is horseshit! If you are so utterly clueless and stupid to actually do that, I would have fired you from my company, on the spot, and been miffed about hiring you in the first place. You will NEVER use actual entity data in schema because there is no such thing as "immutable attributes" in real-life. Not even back account numbers or social security number. There is no such thing at all!
Thus it is paramount to separate data from schema and give each entity an autogenerated primary key that simply cannot face real-world pressure to change its value. Thus, primary keys created by this principle, ARE NOT ATTRIBUTES OF AN ENTITY!
This implementation follows number of principles.
Content-Type: application/json
./api/v1/employee/4121/reservation/1412/
.?fields=firstname,lastname&order=asc
)/user/<id>
)./api/v2/user
). This allows supporting multiple versions and very simple interface of obsoleted API versions – they simply are not found. No code to write about “wrong version requested”…/api/v1/employee/<id>
), "search" type requests shall not be accessible through endpoints that have parametrized the identity of the searched entity. (Correct would be; /api/v1/employee/
).Method | Action | Idempontence |
---|---|---|
GET |
search/fetch | Idempotent |
POST |
create | Non-idempotent |
PUT |
update | Idempotent |
PATCH |
(special) | Non-Idempotent |
DELETE |
delete | Idempotent |
This implementation strives to follow these principles when ever possible. Most important of the response code usages involved signaling if the requested resource is available at all. For resource (endpoint) + method combinations and their logical meaning, following table should be used:
+---------------+---------+--------+---------+--------+--------+
| Resource | POST | GET | PUT | PATCH | DELETE |
+---------------+---------+--------+---------+--------+--------+
| /entity | Create | Search | 405 | 405 | 405 |
| /entity/<:id> | 405 | Fetch | Replace | Update | Delete |
+---------------+---------+--------+---------+--------+--------+
Reply 405 Method Not Allowed
should be the only 4xx response used to indicate unavailable method + endpoint combinations.
200 OK
202 Accepted
400 Bad Request
401 Unauthorized
404 Not Found
405 Method Not Allowed
406 Not Acceptable
Idempotent
Verb: Fetch / Search (SELECT
)
Query Parameters: FETCH: maybe, SEARCH: always
Accesses: FETCH: Entity Identifying Endpoint (/api/entity/<int:id>
), SEARCH: Generic Endpoint (/api/entity
)
Send Payload: None
Get Payload: FETCH: entity object, SEARCH: list of entity objects (0 ... N)
First, the more obvious, is be called the "fetch" type. These GET requests access Entity Identifying Endpoints and expect to receive one entity object in JSON format.
Second type is the "search" type, which accesses Generic Entity Endpoint with any number of search/filtering criteria in Query Parameters. These requests expect to receive a list JSON, containing zero to N entity objects.
Fetch type GET queries usually do not support Query parameters, but if deemed necessary, an implementation may choose to define them.
When "fetch" yields no results, response "404 Not Found" is returned. When "search" type request yields no results, an empty list is returned with code "200 OK".
Search GET : Possible Replies
Code Payload Description
200 OK 'data': [{},...] Success. List of entities returned.
400 Bad Request None Data/structure error.
401 Unauthorized None Access/authorization error.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Argument error.
Fetch GET : Possible Replies
Code Payload Description
200 OK 'data': {} Success. Entity is returned.
400 Bad Request None Data/structure error.
401 Unauthorized None Access/authorization error.
404 Not Found None Entity by ID not found.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Argument error.
Non-idempotent
Verb: Create (INSERT
)
Query Parameters: None
Access: Generic Endpoint (/api/entity
)
Send Payload: Complete entity object JSON
Get Payload: Entity ID: { 'id': <int:id>}
POST Request accesses Generic Endpoint (/api/entity
) with entity object JSON and the server creates a new database record (row). Response will always contain the ID of the created entity . Client may use or discard this information at its discretion.
Possible Replies
Code Payload Description
200 OK 'data': {'id': <int>} Success. New entity created.
202 Accepted 'data': {'id': <int>} Asyncronous action queued.
400 Bad Request None Data/structure error.
401 Unauthorized None Access/authorization error.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Argument error.
Response code 202
usage should be carefully considered. If one API endpoint accessed with one method, does not return both asyncronous and immediate response "values", code 200
should be used instead.
Idempotent
Verb: Update (UPDATE
)
Query Parameters: None
Access: Entity Identifying Endpoint (/api/entity/<int:id>
)
Send Payload: Complete or partial entity object JSON
Get Payload: None
PUT Request accesses Entity Identifying Endpoint (api/entity/<int:id>
) with entity object JSON payload, containing those attributes that need to be updated and their new values. Successul response will have no payload.
Possible Replies
Code Payload Description
200 OK 'data': {'id': <int>} Success. Entity updated.
400 Bad Request None Data/structure error.
401 Unauthorized None Access/authorization error.
404 Not Found None Entity by ID not found.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Argument error.
Non-idemptent
Verb: N/A
Query Parameters: None
Access: Either Entity Identifying Endpoint (api/entity/<int:id>
) OR Generic Endpoint (/api/entity
)
Send Payload: Implementation specific
Get Payload: Implementation specific
PATCH Request accesses Entity Identifying Endpoint (api/entity/<int:id>
) OR Generic Endpoint (/api/entity
) (depending which one makes logical sense) with special JSON payload (specifications up to the implementation). The special payload contains instructions or commands (as allowed by the implementation) that cannot be expressed simply as an entity attribute update.
An example might be an archive command to api/entity
with payload { 'archive': {'olderthan': '2019-01-01'} }
, which would cause the server to archive entities older than the specified date (possibly moving to a compressed .tar archive, maybe).
Alternatively, PATCH Request may limit its effects to the entity, but requests an action that is not idempotent, such as "increment usage count" (something which you never want to implement as fetch-update action, to avoid race conditions).
Need for response payload and its content are also entirely implementation specific.
Possible Replies
Code Payload Description
200 OK 'data': {'id': <int>} Success. Entity updated.
400 Bad Request None Data/structure error.
401 Unauthorized None Access/authorization error.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Argument error.
Idempotent
Verb: Delete (DELETE
)
Query Parameters: None
Access: Entity Identifying Endpoint (/api/entity/<int:id>
)
Send Payload: None
Get Payload: None
DELETE Request accesses Entity Identifying Endpoint (api/entity/<int:id>
) and carries no payload. Response will neither carry payload.
At first, DELETE might not seem like idempotent, but the fact that you can delete a specific entity only once and thenafter only receive 404 Not Found replies, effectively means that no matter how many times the same DELETE is repeated, the database state has the sone end result.
Possible Replies
Code Payload Description
200 OK None Success.
401 Unauthorized None Access/authorization error.
404 Not Found None Entity by ID not found.
405 Method not allowed None Endpoint + method combo not supported.
406 Not Acceptable None Foreign key violation, or other reason.
Service | Methods | Endpoint | Documentation |
---|---|---|---|
send_ui | GET | / | Send static content (HTML/CSS/JS/images/...). |
send_ui | GET | /<path:path> | Send static content (HTML/CSS/JS/images/...). |
api_not_implemented | POST,PUT,GET,DELETE,PATCH | /api | Catch-all route for '/api*' access attempts that do not match any defined routes. "405 Method Not Allowed" JSON reply is returned. |
api_doc | GET | /api.html | JSON API Documentation. Generates API document from the available endpoints. This functionality relies on PEP 257 (https://www.python.org/dev/peps/pep-0257/) convention for docstrings and Flask micro framework route ('rule') mapping to generate basic information listing on all the available REST API functions. This call takes no arguments. GET /sys/api List of API endpoints is returned in JSON. GET /api.html The README.md from /api is prefixed to HTML content. List of API endpoints is included as a table. |
api_not_implemented | POST,PUT,GET,DELETE,PATCH | /api/ | Catch-all route for '/api*' access attempts that do not match any defined routes. "405 Method Not Allowed" JSON reply is returned. |
api_not_implemented | POST,PUT,GET,DELETE,PATCH | /api/<path:path> | Catch-all route for '/api*' access attempts that do not match any defined routes. "405 Method Not Allowed" JSON reply is returned. |
api_file | GET | /api/file | List of downloadable file, with optional type filtering. Allowed types are "vm" and "usb". GET /api/file GET /api/file/usb GET /api/file/vm Query parameters: (none implemented) API returns 200 OK and: { ..., "data" : [ { TBA }, ... ], ... } |
api_file | GET | /api/file/<any("vm","usb"):ftype> | List of downloadable file, with optional type filtering. Allowed types are "vm" and "usb". GET /api/file GET /api/file/usb GET /api/file/vm Query parameters: (none implemented) API returns 200 OK and: { ..., "data" : [ { TBA }, ... ], ... } |
api_file_id | PUT,GET | /api/file/<int:id> | Database table row endpoint. Retrieve (GET) or update (PUT) record. |
flow_chunk_upload | POST,GET | /api/file/flow | Return 200 if given chunk already exists, return 204 if not. |
api_file_owned | GET | /api/file/owned | Return JSON listing of files owned by currently authenticated person. Slightly 'special' endpoint that accepts only GET method and no parameters of any kind. Data is returned based on the SSO session role. Specially created for Upload and Manage UI, to list user's files. |
api_file_schema | GET | /api/file/schema | Create data schema JSON for client FORM creation. |
sso_state | GET | /api/sso | Returns a sigle item JSON: { "role": "[anonymous|student|teacher]" }. This also implicitly indicates the authentication state (anonymous = not authenticated). |
sso_login | GET | /api/sso/login | This is the landing URI from SSO login page. SSO REST API is re-queried and session is updated accordingly. Finally, 'destination' URL parameter is used to redirect the broser to the final location - persumably the page from where the "login" link/button was pressed. |
sso_logout | GET | /api/sso/logout | This endpoint sets UID to None and ROLE to 'anonymous' in the session, thus effectively logging the user out. |
download | GET | /download/<path:path> | None |
flow_process_status | GET | /sse/flow-upload-status | SSE endpoint to supply data to event listener. Required URL parameters: 'filename' and 'flowid'. RETURN CODES 200 OK no name conflict (GET) / successful assembly (POST) 400 BadRequest Malformed requests (no 'filename' and/or 'flowid'). 401 Unauthorized Not an active teacher |
api_doc | GET | /sys/api | JSON API Documentation. Generates API document from the available endpoints. This functionality relies on PEP 257 (https://www.python.org/dev/peps/pep-0257/) convention for docstrings and Flask micro framework route ('rule') mapping to generate basic information listing on all the available REST API functions. This call takes no arguments. GET /sys/api List of API endpoints is returned in JSON. GET /api.html The README.md from /api is prefixed to HTML content. List of API endpoints is included as a table. |
show_flask_config | GET | /sys/cfg | Middleware (Flask application) configuration. Sensitive entries are censored. |