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 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.:

  1. List of all persons: <domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person
  2. Data of person 123: <domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123
  3. Addresses of person 123: <domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address
  4. 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 acessible 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.

If this is not wished:

  • HTTP AUTH might be used (configured via webserver)
  • Any other webserver based access restriction method
  • or the QFQ internal ‘HTTP header token based authorization’.

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}}' }}

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).