task('specs') ->param('version', 'latest', new Text(8), 'Spec version', true) ->param('mode', 'normal', new WhiteList(['normal', 'mocks']), 'Spec Mode', true) ->action(function ($version, $mode) use ($register) { $db = $register->get('db'); $redis = $register->get('cache'); $appRoutes = App::getRoutes(); $response = new Response(new HttpResponse()); $mocks = ($mode === 'mocks'); App::setResource('request', fn () => new Request); App::setResource('response', fn () => $response); App::setResource('db', fn () => $db); App::setResource('cache', fn () => $redis); $platforms = [ 'client' => APP_PLATFORM_CLIENT, 'server' => APP_PLATFORM_SERVER, 'console' => APP_PLATFORM_CONSOLE, ]; $authCounts = [ 'client' => 1, 'server' => 2, 'console' => 1, ]; $keys = [ APP_PLATFORM_CLIENT => [ 'Project' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Project', 'description' => 'Your project ID', 'in' => 'header', ], 'JWT' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-JWT', 'description' => 'Your secret JSON Web Token', 'in' => 'header', ], 'Locale' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Locale', 'description' => '', 'in' => 'header', ], ], APP_PLATFORM_SERVER => [ 'Project' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Project', 'description' => 'Your project ID', 'in' => 'header', ], 'Key' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Key', 'description' => 'Your secret API key', 'in' => 'header', ], 'JWT' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-JWT', 'description' => 'Your secret JSON Web Token', 'in' => 'header', ], 'Locale' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Locale', 'description' => '', 'in' => 'header', ], ], APP_PLATFORM_CONSOLE => [ 'Project' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Project', 'description' => 'Your project ID', 'in' => 'header', ], 'Key' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Key', 'description' => 'Your secret API key', 'in' => 'header', ], 'JWT' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-JWT', 'description' => 'Your secret JSON Web Token', 'in' => 'header', ], 'Locale' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Locale', 'description' => '', 'in' => 'header', ], 'Mode' => [ 'type' => 'apiKey', 'name' => 'X-Appwrite-Mode', 'description' => '', 'in' => 'header', ], ], ]; foreach (['swagger2', 'open-api3'] as $format) { foreach ($platforms as $platform) { $routes = []; $models = []; $services = []; foreach ($appRoutes as $key => $method) { foreach ($method as $route) { /** @var \Utopia\Route $route */ $routeSecurity = $route->getLabel('sdk.auth', []); $sdkPlatofrms = []; foreach ($routeSecurity as $value) { switch ($value) { case APP_AUTH_TYPE_SESSION: $sdkPlatofrms[] = APP_PLATFORM_CLIENT; break; case APP_AUTH_TYPE_KEY: $sdkPlatofrms[] = APP_PLATFORM_SERVER; break; case APP_AUTH_TYPE_JWT: $sdkPlatofrms[] = APP_PLATFORM_SERVER; break; case APP_AUTH_TYPE_ADMIN: $sdkPlatofrms[] = APP_PLATFORM_CONSOLE; break; } } if (empty($routeSecurity)) { $sdkPlatofrms[] = APP_PLATFORM_CLIENT; } if (!$route->getLabel('docs', true)) { continue; } if ($route->getLabel('sdk.mock', false) && !$mocks) { continue; } if (!$route->getLabel('sdk.mock', false) && $mocks) { continue; } if (empty($route->getLabel('sdk.namespace', null))) { continue; } if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlatofrms)) { continue; } $routes[] = $route; $modelLabel = $route->getLabel('sdk.response.model', 'none'); \is_array($modelLabel) ? \array_map(function ($m) use ($response) { return $response->getModel($m); }, $modelLabel) : $response->getModel($modelLabel); } } foreach (Config::getParam('services', []) as $service) { if ( !isset($service['docs']) // Skip service if not part of the public API || !isset($service['sdk']) || !$service['docs'] || !$service['sdk'] ) { continue; } $services[] = [ 'name' => $service['key'] ?? '', 'description' => $service['subtitle'] ?? '', ]; } $models = $response->getModels(); foreach ($models as $key => $value) { if ($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) { unset($models[$key]); } } switch ($format) { case 'swagger2': $formatInstance = new Swagger2(new App('UTC'), $services, $routes, $models, $keys[$platform], $authCounts[$platform] ?? 0); break; case 'open-api3': $formatInstance = new OpenAPI3(new App('UTC'), $services, $routes, $models, $keys[$platform], $authCounts[$platform] ?? 0); break; default: throw new Exception('Format not found: ' . $format); break; } $specs = new Specification($formatInstance); $endpoint = App::getEnv('_APP_HOME', '[HOSTNAME]'); $email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); $formatInstance ->setParam('name', APP_NAME) ->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)') ->setParam('endpoint', 'https://HOSTNAME/v1') ->setParam('version', APP_VERSION_STABLE) ->setParam('terms', $endpoint . '/policy/terms') ->setParam('support.email', $email) ->setParam('support.url', $endpoint . '/support') ->setParam('contact.name', APP_NAME . ' Team') ->setParam('contact.email', $email) ->setParam('contact.url', $endpoint . '/support') ->setParam('license.name', 'BSD-3-Clause') ->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE') ->setParam('docs.description', 'Full API docs, specs and tutorials') ->setParam('docs.url', $endpoint . '/docs'); if ($mocks) { $path = __DIR__ . '/../config/specs/' . $format . '-mocks-' . $platform . '.json'; if (!file_put_contents($path, json_encode($specs->parse()))) { throw new Exception('Failed to save mocks spec file: ' . $path); } Console::success('Saved mocks spec file: ' . realpath($path)); continue; } $path = __DIR__ . '/../config/specs/' . $format . '-' . $version . '-' . $platform . '.json'; if (!file_put_contents($path, json_encode($specs->parse()))) { throw new Exception('Failed to save spec file: ' . $path); } Console::success('Saved spec file: ' . realpath($path)); } } });