REST¶
Via REST it’s possible to access the QFQ based application. Each REST API endpoint has to be defined as a QFQ Form.
This describes the server side (=QFQ is server). For client access check REST Client.
The QFQ REST api implements the four most used REST HTTP methods:
- GET - Read
Shows a list of database records or a single record. The QFQ form holds the definition which and what to show.
List:
curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/Data (id=123):
curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/123- POST - Create new record
The QFQ form defines wich columns will be written in which table. Most of QFQ Form functionality can be used. Example:
curl -X POST "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/" -d '{"name":"Miller","firstname":"Joe"}'- PUT - Update a record
Similar to POST, but a given record will be updated.
curl -X PUT "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/123" -d '{"name":"Miller","firstname":"Joe"}'- DELETE - Delete a record
Similar to a QFQ Delete form.
curl -X DELETE "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/123"
All data will be imported / exported in JSON notation.
Any QFQ form becomes a REST form via: Form > Access > Permit REST: get / insert / update / delete
If the REST endpoint specifies an unknown form or access is forbidden, an HTTP error is reported.
Endpoint¶
Tip
The basic REST API endpoint: <domain>/typo3conf/ext/qfq/Classes/Api/rest.php
<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/<level1>/<id1>/<level2>/<id2>/.../?<var1>=<value1>&...
Append level names and ids after .../rest.php/, each separated by ‘/’ .
E.g.:
- List of all persons:
<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person - Data of person 123:
<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123 - Addresses of person 123:
<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address - Address details of address 45 from person 123:
<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address/45
QFQ ‘Forms’ are used as a ‘container’ (to define all details).
Tip
The QFQ form name represents the level name.
Only the last <level> of an URI will be processed. The former ones are just to fulfil a good looking REST API.
Note
Each level name (=form name) is available via STORE_CLIENT and name _formX. E.g. in example
(1) {{_form1:C:alnumx}}=person and {{_form2:C:alnumx}}=address.
Each level id is available via STORE_CLIENT and name _idX. E.g. in example
(2) {{_id1:C}}=123 and {{_id2:C}}=45.
Also the id after the last level in the URI path, 123 in example (2) and 45 in example (4), is copied to
variable r in STORE_TYPO3, access it via {{r:T}}.
GET - Read¶
A REST (GET) form has two modes:
- data
- Specific content to a given id. Defined via
form.parameter.restSqlData. This mode is selected if there is an id>0 given. - list
- A list of records will be exported. Defined via
form.parameter.restSqlList. This mode is selected if there is no id or id=0.
Note
There are no native-FormElements necessary or loaded. Action FormElements will be processed.
To simplify access to id parameter of the URI, a mapping is possible via ‘form.parameter.restParam’.
E.g. restParam=pId,adrId with example d) makes {{pId:C}}=123 and {{adrId:C}}=45. The order of variable
names corresponds to the position in the URI. _id1 is always mapped to the first parameter name, _id2 to
the second one and so on.
GET Variables provided via URL are available via STORE_CLIENT as usual.
Form
| Attribute | Description |
|---|---|
| name | <level> Mandatory. Level name (Endpoint) in URI. |
| table | Mandatory. Name of the primary table |
| Permit REST | get Mandatory. The form can be loaded in REST mode. |
Form.parameter
| Attribute | Description |
|---|---|
| restSqlData | Mandatory. SQL query selects content shown in data mode.
| restSqlData={{!SELECT id, name, gender FROM Person WHERE id='{{r:T0}}'' }} |
| restSqlList | Mandatory. SQL query selects content shown in data mode.
| restSqlData={{!SELECT id, name FROM Person }} |
| restParam | Optional. CSV list of variable names. E.g.: restParam=pId,adrId |
| restToken | Optional. User defined string or dynamic token (see :ref:restAuthorization). |
Note
There are no Special column names available in restSqlData or restSqlList. Also there are no
SIPs possible, cause REST typically does not offer sessions/cookies (which are necessary for SIPs).
Important
If there is an ìd given, a record in the named primary with the specified table has to exist.
If not, an error is thrown.
POST - Insert¶
Form
| Attribute | Description |
|---|---|
| name | <level> Mandatory. Level name (Endpoint) in URI. |
| table | Mandatory. Name of the primary table |
| Permit REST | insert Mandatory. The form can be loaded in REST mode. |
| id | Missing or ‘0’. |
Form.parameter
| Attribute | Description |
|---|---|
| restParam | Optional. CSV list of variable names. E.g.: restParam=pId,adrId |
| restToken | Optional. User defined string or dynamic token (see Authorization). |
| restSqlPostPut | Optional. Instead of returning the last_insert_id, a customized result might be
specified. E.g. {{! SELECT id, token FROM Token WHERE id={{id:R0}} }} |
FormElement:
- For each column to save one FormElement with
FE.name=<column>is necessary. - A regular QFQ form can be used as REST Post endpoint.
PUT - Update¶
Form
| Attribute | Description |
|---|---|
| name | <level> Mandatory. Level name (Endpoint) in URI. |
| table | Mandatory. Name of the primary table |
| Permit REST | update Mandatory. The form can be loaded in REST mode. |
| id | >0 |
Form.parameter
| Attribute | Description |
|---|---|
| restParam | Optional. CSV list of variable names. E.g.: restParam=pId,adrId |
| restToken | Optional. User defined string or dynamic token (see Authorization). |
FormElement:
- For each column to save one FormElement with
FE.name=<column>is necessary. - A regular QFQ form can be used as REST Post endpoint
DELETE - Delete¶
Form
| Attribute | Description |
|---|---|
| name | <level> Mandatory. Level name (Endpoint) in URI. |
| table | Mandatory. Name of the primary table |
| Permit REST | delete Mandatory. The form can be loaded in REST mode. |
| id | >0 |
Form.parameter
| Attribute | Description |
|---|---|
| restParam | Optional. CSV list of variable names. E.g.: restParam=pId,adrId |
| restToken | Optional. User defined string or dynamic token (see Authorization). |
Note
There are no native-FormElements necessary - but might exist for dependent records to delete. Action FormElements will be processed.
Authorization¶
A QFQ form is only accessible via REST API, if Form.permitRest enables one of the HTTP Methods: get, post, put, delete
Permit New or Permit Edit don’t apply to QFQ forms called via REST.
Important
By default, the REST API is public accessible.
Restrict access via:
- HTTP AUTH (configured via web server).
- Any other web server based access restriction method.
- QFQ internal ‘HTTP header token based authorization’ (see below).
Token based authorization¶
A form will require a ‘token based authorization’, as soon as there is a form.parameter.restToken defined.
Therefore the HTTP Header ‘Authorization’ has to be set with token=<secret token>. The ‘secret token’ will
be checked against the server.
Example:
form.parameter.restToken=myCrypticString0123456789
Test via commandline: curl -X GET -H 'Authorization: Token token=myCrypticString0123456789' "http://localhost/qfq/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address/"
The static setup with form.parameter.restToken=myCrypticString0123456789 is fine, as long as only one token
exist. In case of multiple tokens, replace the static string against a SQL query.
Tip
The HTML Header Authorization token is available in STORE_CLIENT via ‘{{Authorization:C:alnumx}}.
Best Practice: For example all created tokens are saved in a table ‘Auth’ with a column ‘token’. Define:
form.parameter.restToken={{SELECT a.token FROM Auth AS a WHERE a.token='{{Authorization:C:alnumx}}' }}
An invalid or empty Authorization string won’t select any record in form.parameter.restSqlList / form.parameter.restSqlData.
To restrict access to a subset of data, just save the limitations inside the Auth record and update the query to check it:
form.parameter.restToken={{SELECT a.token FROM Auth AS a WHERE a.token='{{Authorization:C:alnumx}}'}}
form.parameter.restSqlList={{!SELECT p.id, p.name, p.email FROM Person AS p, Auth AS a WHERE a.token='{{Authorization:C:alnumx}}' AND a.attribute=p.attribute}}
form.parameter.restSqlData={{!SELECT p.* FROM Person AS p, Auth AS a WHERE a.token='{{Authorization:C:alnumx}}' AND a.attribute=p.attribute AND p.id='{{r:T0}}' }}
If authorization is denied, the request will be answered with a delay of 3 seconds (configured via securityFailedAuthDelay).