From 3ff66179c5fb9bfcd77906475e10381f9f12f3c0 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 8 Apr 2021 10:39:23 +0200 Subject: [PATCH 1/5] feat: add document response model that extends any type --- app/config/events.php | 6 +-- app/controllers/api/database.php | 14 ++--- src/Appwrite/Utopia/Response.php | 5 +- src/Appwrite/Utopia/Response/Filters/V06.php | 1 + .../Utopia/Response/Model/Document.php | 52 +++++++++++++++++++ 5 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 src/Appwrite/Utopia/Response/Model/Document.php diff --git a/app/config/events.php b/app/config/events.php index 601b502163..ed4b6da2b9 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -84,17 +84,17 @@ return [ ], 'database.documents.create' => [ 'description' => 'This event triggers when a database document is created.', - 'model' => Response::MODEL_ANY, + 'model' => Response::MODEL_DOCUMENT, 'note' => '', ], 'database.documents.update' => [ 'description' => 'This event triggers when a database document is updated.', - 'model' => Response::MODEL_ANY, + 'model' => Response::MODEL_DOCUMENT, 'note' => '', ], 'database.documents.delete' => [ 'description' => 'This event triggers when a database document is deleted.', - 'model' => Response::MODEL_ANY, + 'model' => Response::MODEL_DOCUMENT, 'note' => '', ], 'storage.files.create' => [ diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 2c32ae981e..f33b2e1351 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -294,7 +294,7 @@ App::post('/v1/database/collections/:collectionId/documents') ->label('sdk.description', '/docs/references/database/create-document.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ANY) + ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).') ->param('data', [], new JSON(), 'Document data as JSON object.') ->param('read', null, new ArrayList(new Text(64)), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true) @@ -401,7 +401,7 @@ App::post('/v1/database/collections/:collectionId/documents') $response ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($data, Response::MODEL_ANY) + ->dynamic($data, Response::MODEL_DOCUMENT) ; }); @@ -478,7 +478,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId') ->label('sdk.description', '/docs/references/database/get-document.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ANY) + ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).') ->param('documentId', null, new UID(), 'Document unique ID.') ->inject('response') @@ -494,7 +494,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId') throw new Exception('No document found', 404); } - $response->dynamic($document, Response::MODEL_ANY); + $response->dynamic($document, Response::MODEL_DOCUMENT); }); App::patch('/v1/database/collections/:collectionId/documents/:documentId') @@ -508,7 +508,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') ->label('sdk.description', '/docs/references/database/update-document.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ANY) + ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).') ->param('documentId', null, new UID(), 'Document unique ID.') ->param('data', [], new JSON(), 'Document data as JSON object.') @@ -566,7 +566,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId') ->setParam('data', $data->getArrayCopy()) ; - $response->dynamic($data, Response::MODEL_ANY); + $response->dynamic($data, Response::MODEL_DOCUMENT); }); App::delete('/v1/database/collections/:collectionId/documents/:documentId') @@ -614,7 +614,7 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId') } $events - ->setParam('payload', $response->output($document, Response::MODEL_ANY)) + ->setParam('payload', $response->output($document, Response::MODEL_DOCUMENT)) ; $audits diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index e7f7e4e84e..0bed14e45c 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -15,6 +15,7 @@ use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Continent; use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; +use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; @@ -61,6 +62,7 @@ class Response extends SwooleResponse const MODEL_COLLECTION = 'collection'; const MODEL_COLLECTION_LIST = 'collectionList'; const MODEL_RULE = 'rule'; + const MODEL_DOCUMENT = 'document'; const MODEL_DOCUMENT_LIST = 'documentList'; // Users @@ -145,7 +147,7 @@ class Response extends SwooleResponse ->setModel(new ErrorDev()) // Lists ->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION)) - ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_ANY)) + ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT)) ->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER)) ->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION)) ->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG, false)) @@ -169,6 +171,7 @@ class Response extends SwooleResponse // Entities ->setModel(new Permissions()) ->setModel(new Collection()) + ->setModel(new ModelDocument()) ->setModel(new Rule()) ->setModel(new Log()) ->setModel(new User()) diff --git a/src/Appwrite/Utopia/Response/Filters/V06.php b/src/Appwrite/Utopia/Response/Filters/V06.php index 137ecbfb5a..13ee89cbb7 100644 --- a/src/Appwrite/Utopia/Response/Filters/V06.php +++ b/src/Appwrite/Utopia/Response/Filters/V06.php @@ -108,6 +108,7 @@ class V06 extends Filter { break; case Response::MODEL_ANY : + case Response::MODEL_DOCUMENT : $parsedResponse = $content; break; diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php new file mode 100644 index 0000000000..a8a9f80970 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Document.php @@ -0,0 +1,52 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Document ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$collection', [ + 'type' => self::TYPE_STRING, + 'description' => 'Collection ID.', + 'default' => '', + 'example' => '5e5ea5c15117e', + ]) + ->addRule('$permissions', [ + 'type' => Response::MODEL_PERMISSIONS, + 'description' => 'Document permissions.', + 'default' => new \stdClass, + 'example' => new \stdClass, + 'array' => false, + ]); + } +} From d8fd30cffabc296283449e2a8d2b11f2166d6e71 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 8 Apr 2021 10:39:44 +0200 Subject: [PATCH 2/5] feat: filter response models in swagger spec --- src/Appwrite/Specification/Format/Swagger2.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 4dd0406088..b91546693c 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -81,7 +81,9 @@ class Swagger2 extends Format $output['securityDefinitions']['Mode']['x-appwrite'] = ['demo' => '']; } - foreach ($this->routes as $route) { /* @var $route \Utopia\Route */ + $usedModels = []; + + foreach ($this->routes as $route) { /** @var \Utopia\Route $route */ $url = \str_replace('/v1', '', $route->getURL()); $scope = $route->getLabel('scope', ''); $hide = $route->getLabel('sdk.hide', false); @@ -148,6 +150,7 @@ class Swagger2 extends Format ], ]; } else { + $usedModels[] = $model->getType(); $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'schema' => [ @@ -232,7 +235,7 @@ class Swagger2 extends Format $node['format'] = 'format'; $node['x-example'] = 'password'; break; - case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */ + case 'Utopia\Validator\Range': /** @var \Utopia\Validator\Range $validator */ $node['type'] = 'integer'; $node['format'] = 'int32'; $node['x-example'] = $validator->getMin(); @@ -249,7 +252,7 @@ class Swagger2 extends Format $node['format'] = 'url'; $node['x-example'] = 'https://example.com'; break; - case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */ + case 'Utopia\Validator\WhiteList': /** @var \Utopia\Validator\WhiteList $validator */ $node['type'] = 'string'; $node['x-example'] = $validator->getList()[0]; break; @@ -310,6 +313,10 @@ class Swagger2 extends Format } foreach ($this->models as $model) { + if (!in_array($model->getType(), $usedModels)) { + continue; + } + $required = $model->getRequired(); $rules = $model->getRules(); From 8bac3caeb5cb7fca9d984ab171d9e586b1774c97 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 8 Apr 2021 10:46:45 +0200 Subject: [PATCH 3/5] feat: filter response models in openapi3 spec --- src/Appwrite/Specification/Format/OpenAPI3.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 3c62daf5f7..6b32f10057 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -83,7 +83,9 @@ class OpenAPI3 extends Format $output['components']['securitySchemes']['Mode']['x-appwrite'] = ['demo' => '']; } - foreach ($this->routes as $route) { /* @var $route \Utopia\Route */ + $usedModels = []; + + foreach ($this->routes as $route) { /** @var \Utopia\Route $route */ $url = \str_replace('/v1', '', $route->getURL()); $scope = $route->getLabel('scope', ''); $hide = $route->getLabel('sdk.hide', false); @@ -146,6 +148,7 @@ class OpenAPI3 extends Format // ], ]; } else { + $usedModels[] = $model->getType(); $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => $model->getName(), 'content' => [ @@ -236,7 +239,7 @@ class OpenAPI3 extends Format $node['schema']['format'] = 'format'; $node['schema']['x-example'] = 'password'; break; - case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */ + case 'Utopia\Validator\Range': /** @var \Utopia\Validator\Range $validator */ $node['schema']['type'] = 'integer'; $node['schema']['format'] = 'int32'; $node['schema']['x-example'] = $validator->getMin(); @@ -253,7 +256,7 @@ class OpenAPI3 extends Format $node['schema']['format'] = 'url'; $node['schema']['x-example'] = 'https://example.com'; break; - case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */ + case 'Utopia\Validator\WhiteList': /** @var \Utopia\Validator\WhiteList $validator */ $node['schema']['type'] = 'string'; $node['schema']['x-example'] = $validator->getList()[0]; break; @@ -309,6 +312,10 @@ class OpenAPI3 extends Format } foreach ($this->models as $model) { + if (!in_array($model->getType(), $usedModels)) { + continue; + } + $required = $model->getRequired(); $rules = $model->getRules(); From ccf114120e1bef39f4ab06b3adb1253aad299cce Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 8 Apr 2021 11:24:41 +0200 Subject: [PATCH 4/5] fix: add nested models in models --- src/Appwrite/Specification/Format/OpenAPI3.php | 8 +++++++- src/Appwrite/Specification/Format/Swagger2.php | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 6b32f10057..591fda709a 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -310,7 +310,13 @@ class OpenAPI3 extends Format $output['paths'][$url][\strtolower($route->getMethod())] = $temp; } - + foreach ($this->models as $model) { + foreach ($model->getRules() as $rule) { + if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { + $usedModels[] = $rule['type']; + } + } + } foreach ($this->models as $model) { if (!in_array($model->getType(), $usedModels)) { continue; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index b91546693c..0e639e9a86 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -4,6 +4,7 @@ namespace Appwrite\Specification\Format; use Appwrite\Specification\Format; use Appwrite\Template\Template; +use Appwrite\Utopia\Response\Model; use stdClass; class Swagger2 extends Format @@ -311,7 +312,13 @@ class Swagger2 extends Format $output['paths'][$url][\strtolower($route->getMethod())] = $temp; } - + foreach ($this->models as $model) { + foreach ($model->getRules() as $rule) { + if (!in_array($rule['type'], ['string', 'integer', 'boolean', 'json', 'float'])) { + $usedModels[] = $rule['type']; + } + } + } foreach ($this->models as $model) { if (!in_array($model->getType(), $usedModels)) { continue; From 3cc08c849f04229229eec1ba2390ba18feff23d1 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 8 Apr 2021 11:27:59 +0200 Subject: [PATCH 5/5] fix: add error types --- src/Appwrite/Specification/Format/OpenAPI3.php | 2 +- src/Appwrite/Specification/Format/Swagger2.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 591fda709a..f01673d3a5 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -318,7 +318,7 @@ class OpenAPI3 extends Format } } foreach ($this->models as $model) { - if (!in_array($model->getType(), $usedModels)) { + if (!in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { continue; } diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 0e639e9a86..1d92a0ea3c 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -320,7 +320,7 @@ class Swagger2 extends Format } } foreach ($this->models as $model) { - if (!in_array($model->getType(), $usedModels)) { + if (!in_array($model->getType(), $usedModels) && $model->getType() !== 'error') { continue; }