task('specs') ->param('version', 'latest', new Text(8), 'Spec version', true) ->param('mode', 'normal', new WhiteList(['normal', 'tests']), '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()); $tests = ($mode === 'tests'); App::setResource('request', function() { return new Request; }); App::setResource('response', function() use ($response) { return $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) && !$tests) { continue; } if (!$route->getLabel('sdk.mock', false) && $tests) { 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'); $model = \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($tests) { $path = __DIR__.'/../config/specs/'.$format.'-tests-'.$platform.'.json'; if(!file_put_contents($path, json_encode($specs->parse()))) { throw new Exception('Failed to save tests spec file: '.$path); } Console::success('Saved tests 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)); } } });