From 36640f7742f0a52f3422f002589a6c0f2f079cf7 Mon Sep 17 00:00:00 2001 From: crose <carsten.rose@math.uzh.ch> Date: Fri, 22 Feb 2019 16:54:36 +0100 Subject: [PATCH] First REST implementation with GET,POST,PUT,DELETE and token authorization. --- extension/Documentation/Manual.rst | 102 ++++++++++++++++++++--- extension/Source/api/rest.php | 8 ++ extension/Source/core/QuickFormQuery.php | 5 +- 3 files changed, 100 insertions(+), 15 deletions(-) diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst index 50993de54..ee11a7026 100644 --- a/extension/Documentation/Manual.rst +++ b/extension/Documentation/Manual.rst @@ -7438,7 +7438,7 @@ GET - Read List: ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/`` - Record with id=123: ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/123`` + Data (id=123): ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/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: @@ -7455,11 +7455,9 @@ DELETE - Delete a record ``curl -X DELETE "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/123"`` -All data is exported in JSON notation. +All data will imported / exported in JSON notation. -To define a QFQ form becomes a REST form by enable one or more of: - -Form: Access > Permit REST: get / insert / update / delete +Any QFQ form becomes a REST form via: ``Form > Access > Permit REST: get / insert / update / delete`` Endpoint -------- @@ -7513,7 +7511,9 @@ 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. -There are *no* FormElements. +.. 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 @@ -7548,7 +7548,7 @@ Form.parameter: +-------------------+----------------------------------------------------------------------------------+ | restParam | Optional. CSV list of variable names. E.g.: ``restParam=pId,adrId`` | +-------------------+----------------------------------------------------------------------------------+ -| restToken | Optional. User defined string or dynamic token (see below). | +| restToken | Optional. User defined string or dynamic token (see `restAuthorization`_). | +-------------------+----------------------------------------------------------------------------------+ .. note: @@ -7571,19 +7571,96 @@ Form: +-------------------+------------------------------------------------------------------------------+ | Permit REST | *insert* Mandatory. The form can be loaded in REST mode. | +-------------------+------------------------------------------------------------------------------+ -| id | Missing or '0'. +| 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 `restAuthorization`_). | ++-------------------+----------------------------------------------------------------------------------+ + +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 `restAuthorization`_). | ++-------------------+----------------------------------------------------------------------------------+ + +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 `restAuthorization`_). | ++-------------------+----------------------------------------------------------------------------------+ + +.. note: + + There are *no* native-FormElements necessary - but might exist for dependent records to delete. Action FormElements + will be processed. + + +.. _`restAuthorization`: Authorization ------------- -A QFQ form is only acessible via REST API, if ``Form.permitREST`` enables the HTTP Method (get, post, put, delete) +A QFQ form is only acessible via REST API, if ``Form.permitRest`` enables on of the HTTP Method: **get, post, put, delete** ``Permit New`` or ``Permit Edit`` don't apply to QFQ forms called via REST. @@ -7591,8 +7668,11 @@ A QFQ form is only acessible via REST API, if ``Form.permitREST`` enables the HT By default, the REST API is public accessible. -If this is not wished, HTTP AUTH might be used (configured via webserver) or the -QFQ internal 'HTTP header token based authorization'. +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 ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/extension/Source/api/rest.php b/extension/Source/api/rest.php index 5444ad7e6..ff99752e5 100644 --- a/extension/Source/api/rest.php +++ b/extension/Source/api/rest.php @@ -37,6 +37,7 @@ try { case REQUEST_METHOD_GET: $status = HTTP_200_OK; break; + case REQUEST_METHOD_POST: if ($id != 0) { throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id>0 with HTTP method $method", @@ -48,6 +49,7 @@ try { $data = json_decode(file_get_contents('php://input'), true); $status = HTTP_201_CREATED; break; + case REQUEST_METHOD_PUT: if ($id == 0) { throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id==0 with HTTP method $method", @@ -58,6 +60,7 @@ try { $data = json_decode(file_get_contents('php://input'), true); $status = HTTP_200_OK; break; + case REQUEST_METHOD_DELETE: if ($id == 0) { throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id==0 with HTTP method $method", @@ -67,7 +70,12 @@ try { } $status = HTTP_200_OK; break; + default: + throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => 'Unsupported/unknown HTTP request method', + ERROR_MESSAGE_SUPPORT => 'HTTP Code: ' . $method, + ERROR_MESSAGE_HTTP_STATUS => HTTP_403_METHOD_NOT_ALLOWED + ]), ERROR_UNKNOWN_MODE); break; } diff --git a/extension/Source/core/QuickFormQuery.php b/extension/Source/core/QuickFormQuery.php index c3e2fbe4e..a514d4bbf 100644 --- a/extension/Source/core/QuickFormQuery.php +++ b/extension/Source/core/QuickFormQuery.php @@ -1492,10 +1492,7 @@ class QuickFormQuery { break; default: - throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => 'Unsupported/unknown HTTP request method', - ERROR_MESSAGE_SUPPORT => 'HTTP Code: ' . $method, - ERROR_MESSAGE_HTTP_STATUS => HTTP_403_METHOD_NOT_ALLOWED - ]), ERROR_UNKNOWN_MODE); + throw new CodeException('This code should never be reached', ERROR_CODE_SHOULD_NOT_HAPPEN); } } else { -- GitLab