Fix custom entity id properties
This commit is contained in:
parent
8762bcba90
commit
b5e8273839
4 changed files with 129 additions and 94 deletions
|
@ -55,37 +55,22 @@ App::post('/v1/graphql')
|
||||||
->param('query', '', new Text(1024), 'The query to execute. Max 1024 chars.', true)
|
->param('query', '', new Text(1024), 'The query to execute. Max 1024 chars.', true)
|
||||||
->param('operationName', null, new Text(256), 'Name of the operation to execute', true)
|
->param('operationName', null, new Text(256), 'Name of the operation to execute', true)
|
||||||
->param('variables', [], new JSON(), 'Variables to use in the operation', true)
|
->param('variables', [], new JSON(), 'Variables to use in the operation', true)
|
||||||
|
->param('operations', '', new Text(1024), 'Variables to use in the operation', true)
|
||||||
|
->param('map', '', new Text(1024), 'Variables to use in the operation', true)
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('promiseAdapter')
|
->inject('promiseAdapter')
|
||||||
->inject('gqlSchema')
|
->inject('gqlSchema')
|
||||||
->action(Closure::fromCallable('graphqlRequest'));
|
->action(Closure::fromCallable('graphqlRequest'));
|
||||||
|
|
||||||
App::post('/v1/graphql')
|
|
||||||
->desc('GraphQL Endpoint')
|
|
||||||
->groups(['grapgql'])
|
|
||||||
->label('scope', 'graphql')
|
|
||||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
|
|
||||||
->label('sdk.namespace', 'graphql')
|
|
||||||
->label('sdk.method', 'upload')
|
|
||||||
->label('sdk.description', '/docs/references/graphql/upload.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('abuse-limit', 60)
|
|
||||||
->label('abuse-time', 60)
|
|
||||||
->param('operations', '', new Text(1024), 'Query and variables for operation', true)
|
|
||||||
->param('map', '', new Text(1024), 'Map of form data keys to file replacement dot paths within the operations JSON. For example: "variables.code"', true)
|
|
||||||
->inject('request')
|
|
||||||
->inject('response')
|
|
||||||
->inject('promiseAdapter')
|
|
||||||
->inject('gqlSchema')
|
|
||||||
->action(Closure::fromCallable('graphqlUpload'));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
function graphqlUpload(
|
function graphqlRequest(
|
||||||
|
string $query,
|
||||||
|
?string $operationName,
|
||||||
|
?array $variables,
|
||||||
?string $operations,
|
?string $operations,
|
||||||
?string $map,
|
?string $map,
|
||||||
Appwrite\Utopia\Request $request,
|
Appwrite\Utopia\Request $request,
|
||||||
|
@ -94,9 +79,12 @@ function graphqlUpload(
|
||||||
Type\Schema $gqlSchema
|
Type\Schema $gqlSchema
|
||||||
): void {
|
): void {
|
||||||
$contentType = $request->getHeader('content-type');
|
$contentType = $request->getHeader('content-type');
|
||||||
if (!\str_starts_with($contentType, 'multipart/form-data')) {
|
|
||||||
throw new Exception('Invalid content type', 400);
|
if ($contentType === 'application/graphql') {
|
||||||
|
$query = $request->getSwoole()->rawContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (\str_starts_with($contentType, 'multipart/form-data')) {
|
||||||
$map = \json_decode($map, true);
|
$map = \json_decode($map, true);
|
||||||
$operations = \json_decode($operations, true);
|
$operations = \json_decode($operations, true);
|
||||||
foreach ($map as $fileKey => $locations) {
|
foreach ($map as $fileKey => $locations) {
|
||||||
|
@ -113,27 +101,8 @@ function graphqlUpload(
|
||||||
}
|
}
|
||||||
$query = $operations['query'];
|
$query = $operations['query'];
|
||||||
$variables = $operations['variables'];
|
$variables = $operations['variables'];
|
||||||
|
|
||||||
graphqlRequest($query, null, $variables, $request, $response, $promiseAdapter, $gqlSchema);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
function graphqlRequest(
|
|
||||||
string $query,
|
|
||||||
?string $operationName,
|
|
||||||
?array $variables,
|
|
||||||
Appwrite\Utopia\Request $request,
|
|
||||||
Appwrite\Utopia\Response $response,
|
|
||||||
CoroutinePromiseAdapter $promiseAdapter,
|
|
||||||
Type\Schema $gqlSchema
|
|
||||||
): void {
|
|
||||||
$contentType = $request->getHeader('content-type');
|
|
||||||
if ($contentType === 'application/graphql') {
|
|
||||||
$query = $request->getSwoole()->rawContent();
|
|
||||||
}
|
|
||||||
if (empty($query)) {
|
if (empty($query)) {
|
||||||
throw new Exception('No query supplied.', 400, Exception::GRAPHQL_NO_QUERY);
|
throw new Exception('No query supplied.', 400, Exception::GRAPHQL_NO_QUERY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ use Utopia\CLI\Console;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
use Utopia\Database\Validator\Authorization;
|
use Utopia\Database\Validator\Authorization;
|
||||||
use Utopia\Registry\Registry;
|
|
||||||
use Utopia\Route;
|
use Utopia\Route;
|
||||||
use Utopia\Validator;
|
use Utopia\Validator;
|
||||||
|
|
||||||
|
@ -497,7 +496,7 @@ class Builder
|
||||||
foreach ($collections as $collectionId => $attributes) {
|
foreach ($collections as $collectionId => $attributes) {
|
||||||
$objectType = new ObjectType([
|
$objectType = new ObjectType([
|
||||||
'name' => $collectionId,
|
'name' => $collectionId,
|
||||||
'fields' => $attributes
|
'fields' => \array_merge(["_id" => ['type' => Type::string()]], $attributes),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$attributes = \array_merge(
|
$attributes = \array_merge(
|
||||||
|
@ -695,7 +694,6 @@ class Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
$gqlResponse = $response;
|
$gqlResponse = $response;
|
||||||
|
|
||||||
$request = new Request($swoole);
|
$request = new Request($swoole);
|
||||||
$apiResponse = new Response($response->getSwoole());
|
$apiResponse = new Response($response->getSwoole());
|
||||||
$apiResponse->setContentType(Response::CONTENT_TYPE_NULL);
|
$apiResponse->setContentType(Response::CONTENT_TYPE_NULL);
|
||||||
|
@ -710,31 +708,42 @@ class Builder
|
||||||
|
|
||||||
$utopia->execute($route, $request);
|
$utopia->execute($route, $request);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$gqlResponse->setStatusCode($apiResponse->getStatusCode());
|
self::reassign($gqlResponse, $apiResponse);
|
||||||
$reject($e);
|
$reject($e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self::reassign($gqlResponse, $apiResponse);
|
||||||
|
|
||||||
$result = $apiResponse->getPayload();
|
$result = $apiResponse->getPayload();
|
||||||
|
|
||||||
$gqlResponse->setContentType($apiResponse->getContentType());
|
if ($result['$id']) {
|
||||||
$gqlResponse->setStatusCode($apiResponse->getStatusCode());
|
$result['_id'] = $result['$id'];
|
||||||
|
}
|
||||||
|
|
||||||
if ($apiResponse->getStatusCode() < 200 || $apiResponse->getStatusCode() >= 400) {
|
if ($apiResponse->getStatusCode() < 200 || $apiResponse->getStatusCode() >= 400) {
|
||||||
$reject(new GQLException($result['message'], $apiResponse->getStatusCode()));
|
$reject(new GQLException($result['message'], $apiResponse->getStatusCode()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add headers and cookies from inner to outer response
|
$resolve($result);
|
||||||
// TODO: Add setters to response to allow setting entire array at once
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Response $gqlResponse
|
||||||
|
* @param Response $apiResponse
|
||||||
|
* @return void
|
||||||
|
* @throws \Utopia\Exception
|
||||||
|
*/
|
||||||
|
private static function reassign(Response $gqlResponse, Response $apiResponse): void
|
||||||
|
{
|
||||||
|
$gqlResponse->setContentType($apiResponse->getContentType());
|
||||||
|
$gqlResponse->setStatusCode($apiResponse->getStatusCode());
|
||||||
foreach ($apiResponse->getHeaders() as $key => $value) {
|
foreach ($apiResponse->getHeaders() as $key => $value) {
|
||||||
$gqlResponse->addHeader($key, $value);
|
$gqlResponse->addHeader($key, $value);
|
||||||
}
|
}
|
||||||
foreach ($apiResponse->getCookies() as $name => $cookie) {
|
foreach ($apiResponse->getCookies() as $name => $cookie) {
|
||||||
$gqlResponse->addCookie($name, $cookie['value'], $cookie['expire'], $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly']);
|
$gqlResponse->addCookie($name, $cookie['value'], $cookie['expire'], $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$resolve($result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,18 @@ trait GraphQLBase
|
||||||
public static string $DELETE_INDEX = 'delete_index';
|
public static string $DELETE_INDEX = 'delete_index';
|
||||||
// Documents
|
// Documents
|
||||||
public static string $CREATE_DOCUMENT = 'create_document_rest';
|
public static string $CREATE_DOCUMENT = 'create_document_rest';
|
||||||
public static string $CREATE_CUSTOM_ENTITY = 'create_document_hooks';
|
|
||||||
public static string $GET_DOCUMENTS = 'list_documents';
|
public static string $GET_DOCUMENTS = 'list_documents';
|
||||||
public static string $GET_DOCUMENT = 'get_document';
|
public static string $GET_DOCUMENT = 'get_document';
|
||||||
public static string $UPDATE_DOCUMENT = 'update_document';
|
public static string $UPDATE_DOCUMENT = 'update_document';
|
||||||
public static string $DELETE_DOCUMENT = 'delete_document';
|
public static string $DELETE_DOCUMENT = 'delete_document';
|
||||||
|
|
||||||
|
// Custom Entities
|
||||||
|
public static string $CREATE_CUSTOM_ENTITY = 'create_custom_entity';
|
||||||
|
public static string $GET_CUSTOM_ENTITIES = 'get_custom_entities';
|
||||||
|
public static string $GET_CUSTOM_ENTITY = 'get_custom_entity';
|
||||||
|
public static string $UPDATE_CUSTOM_ENTITY = 'update_custom_entity';
|
||||||
|
public static string $DELETE_CUSTOM_ENTITY = 'delete_custom_entity';
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
public static string $GET_LOCALE = 'get_locale';
|
public static string $GET_LOCALE = 'get_locale';
|
||||||
public static string $LIST_COUNTRIES = 'list_countries';
|
public static string $LIST_COUNTRIES = 'list_countries';
|
||||||
|
@ -414,6 +420,7 @@ trait GraphQLBase
|
||||||
case self::$CREATE_CUSTOM_ENTITY:
|
case self::$CREATE_CUSTOM_ENTITY:
|
||||||
return 'mutation createActor($name: String!, $age: Int!, $alive: Boolean!, $salary: Float, $email: String!, $role: String!, $ip: String, $url: String){
|
return 'mutation createActor($name: String!, $age: Int!, $alive: Boolean!, $salary: Float, $email: String!, $role: String!, $ip: String, $url: String){
|
||||||
actorsCreate(name: $name, age: $age, alive: $alive, salary: $salary, email: $email, role: $role, ip: $ip, url: $url) {
|
actorsCreate(name: $name, age: $age, alive: $alive, salary: $salary, email: $email, role: $role, ip: $ip, url: $url) {
|
||||||
|
_id
|
||||||
name
|
name
|
||||||
age
|
age
|
||||||
alive
|
alive
|
||||||
|
@ -422,6 +429,52 @@ trait GraphQLBase
|
||||||
role
|
role
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
|
case self::$GET_CUSTOM_ENTITIES:
|
||||||
|
return 'query getCustomEntities($name: String!){
|
||||||
|
actorsList(name: $name) {
|
||||||
|
total
|
||||||
|
actors {
|
||||||
|
name
|
||||||
|
age
|
||||||
|
alive
|
||||||
|
salary
|
||||||
|
email
|
||||||
|
role
|
||||||
|
ip
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}';
|
||||||
|
case self::$GET_CUSTOM_ENTITY:
|
||||||
|
return 'query getCustomEntity($id: String!){
|
||||||
|
actorsGet(id: $id) {
|
||||||
|
name
|
||||||
|
age
|
||||||
|
alive
|
||||||
|
salary
|
||||||
|
email
|
||||||
|
role
|
||||||
|
ip
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}';
|
||||||
|
case self::$UPDATE_CUSTOM_ENTITY:
|
||||||
|
return 'mutation updateCustomEntity($id: String!, $name: String!, $age: Int!, $alive: Boolean!, $salary: Float, $email: String!, $role: String!, $ip: String, $url: String){
|
||||||
|
actorsUpdate(id: $id, name: $name, age: $age, alive: $alive, salary: $salary, email: $email, role: $role, ip: $ip, url: $url) {
|
||||||
|
name
|
||||||
|
age
|
||||||
|
alive
|
||||||
|
salary
|
||||||
|
email
|
||||||
|
role
|
||||||
|
ip
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}';
|
||||||
|
case self::$DELETE_CUSTOM_ENTITY:
|
||||||
|
return 'mutation deleteCustomEntity($id: String!){
|
||||||
|
actorsDelete(id: $id)
|
||||||
|
}';
|
||||||
case self::$UPDATE_DOCUMENT:
|
case self::$UPDATE_DOCUMENT:
|
||||||
return 'mutation updateDocument($databaseId: String!, $collectionId: String!, $documentId: String!, $data: Json!, $read: [String!], $write: [String!]){
|
return 'mutation updateDocument($databaseId: String!, $collectionId: String!, $documentId: String!, $data: Json!, $read: [String!], $write: [String!]){
|
||||||
databasesUpdateDocument(databaseId: $databaseId, collectionId: $collectionId, documentId: $documentId, data: $data, read: $read, write: $write) {
|
databasesUpdateDocument(databaseId: $databaseId, collectionId: $collectionId, documentId: $documentId, data: $data, read: $read, write: $write) {
|
||||||
|
|
|
@ -426,7 +426,7 @@ class GraphQLDatabaseServerTest extends Scope
|
||||||
* @depends testCreateEnumAttribute
|
* @depends testCreateEnumAttribute
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function testCreateCustomEntity(): void
|
public function testCreateCustomEntity(): array
|
||||||
{
|
{
|
||||||
$projectId = $this->getProject()['$id'];
|
$projectId = $this->getProject()['$id'];
|
||||||
$query = $this->getQuery(self::$CREATE_CUSTOM_ENTITY);
|
$query = $this->getQuery(self::$CREATE_CUSTOM_ENTITY);
|
||||||
|
@ -447,9 +447,13 @@ class GraphQLDatabaseServerTest extends Scope
|
||||||
'x-appwrite-project' => $projectId,
|
'x-appwrite-project' => $projectId,
|
||||||
], $this->getHeaders()), $gqlPayload);
|
], $this->getHeaders()), $gqlPayload);
|
||||||
|
|
||||||
|
|
||||||
$this->assertArrayNotHasKey('errors', $actor['body']);
|
$this->assertArrayNotHasKey('errors', $actor['body']);
|
||||||
$this->assertIsArray($actor['body']['data']);
|
$this->assertIsArray($actor['body']['data']);
|
||||||
$this->assertIsArray($actor['body']['data']['actorsCreate']);
|
$actor = $actor['body']['data']['actorsCreate'];
|
||||||
|
$this->assertIsArray($actor);
|
||||||
|
|
||||||
|
return $actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetDatabases(): void
|
public function testGetDatabases(): void
|
||||||
|
@ -706,30 +710,30 @@ class GraphQLDatabaseServerTest extends Scope
|
||||||
$this->assertIsArray($document['body']['data']['databasesGetDocument']);
|
$this->assertIsArray($document['body']['data']['databasesGetDocument']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * @depends testCreateCustomEntity
|
* @depends testCreateCustomEntity
|
||||||
// * @throws Exception
|
* @throws Exception
|
||||||
// */
|
*/
|
||||||
// public function testGetCustomEntity($data)
|
public function testGetCustomEntity($data)
|
||||||
// {
|
{
|
||||||
// $projectId = $this->getProject()['$id'];
|
$projectId = $this->getProject()['$id'];
|
||||||
// $query = $this->getQuery(self::$GET_CUSTOM_ENTITY);
|
$query = $this->getQuery(self::$GET_CUSTOM_ENTITY);
|
||||||
// $gqlPayload = [
|
$gqlPayload = [
|
||||||
// 'query' => $query,
|
'query' => $query,
|
||||||
// 'variables' => [
|
'variables' => [
|
||||||
// 'id' => $data['entity']['_id'],
|
'id' => $data['_id'],
|
||||||
// ]
|
]
|
||||||
// ];
|
];
|
||||||
//
|
|
||||||
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
$entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||||
// 'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
// 'x-appwrite-project' => $projectId,
|
'x-appwrite-project' => $projectId,
|
||||||
// ], $this->getHeaders()), $gqlPayload);
|
], $this->getHeaders()), $gqlPayload);
|
||||||
//
|
|
||||||
// $this->assertArrayNotHasKey('errors', $entity['body']);
|
$this->assertArrayNotHasKey('errors', $entity['body']);
|
||||||
// $this->assertIsArray($entity['body']['data']);
|
$this->assertIsArray($entity['body']['data']);
|
||||||
// $this->assertIsArray($entity['body']['data']['actorGet']);
|
$this->assertIsArray($entity['body']['data']['actorsGet']);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @depends testCreateDatabase
|
* @depends testCreateDatabase
|
||||||
|
|
Loading…
Reference in a new issue