From 4ccbfcfefcc8b0be49f8719864851d994d387e39 Mon Sep 17 00:00:00 2001 From: Alexandr Viniychuk Date: Sun, 8 May 2016 23:29:48 -0400 Subject: [PATCH] Generator for schema class added Dependencies updated Controller has been updated for the Symfony v3 Additional checks were implemented GraphQL Schema class was moved to the config file as parameter and is now being used inside the controller --- Command/GenerateSchemaCommand.php | 90 ++++++++++++++++++++++++ Controller/GraphQLController.php | 21 +++--- DependencyInjection/GraphQLExtension.php | 27 +++++-- Processor/Processor.php | 4 +- README.md | 52 +++++++++++--- Resources/config/services.yml | 5 -- 6 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 Command/GenerateSchemaCommand.php diff --git a/Command/GenerateSchemaCommand.php b/Command/GenerateSchemaCommand.php new file mode 100644 index 0000000..d1a5d2e --- /dev/null +++ b/Command/GenerateSchemaCommand.php @@ -0,0 +1,90 @@ +setName('graphql:generate-schema') + ->setDescription('Generates GraphQL Schema class') + ->addArgument('bundle', InputArgument::REQUIRED, 'Bundle to generate class to'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $bundleName = $input->getArgument('bundle'); + if (strpos($bundleName, -6) != 'Bundle') $bundleName .= 'Bundle'; + + $srcPath = realpath($this->getContainer()->getParameter('kernel.root_dir') . '/../src'); + $activeBundles = $this->getContainer()->getParameter('kernel.bundles'); + if (!array_key_exists($bundleName, $activeBundles)) { + $output->writeln('There is no active bundleName: ' . $bundleName); + } + + $graphqlPath = $srcPath . '/' . $bundleName . '/GraphQL'; + $className = 'Schema'; + $classPath = $graphqlPath . '/' . $className . '.php'; + + $inputHelper = $this->getHelper('question'); + $question = new ConfirmationQuestion(sprintf('Confirm creating class at %s ?', $classPath), false); + if (!$inputHelper->ask($input, $output, $question)) { + return; + } + + if (!is_dir($graphqlPath)) { + mkdir($graphqlPath, 0777, true); + } + file_put_contents($classPath, $this->getSchemaClassTemplate($bundleName, $className)); + + $output->writeln('Schema file has been created at'); + $output->writeln($classPath . "\n"); + $output->writeln('Update your app/config/config.yml with the parameter:'); + $output->writeln('graph_ql:'); + $output->writeln(sprintf(' schema_class: %s\GraphQL\%s', $bundleName, $className)); + } + + protected function getSchemaClassTemplate($bundleName, $className = 'Schema') + { + $tpl = <<getQuery()->addFields([ + 'hello' => [ + 'type' => new StringType(), + 'resolve' => function () { + return 'world!'; + } + ] + ]); + } + +} + +TEXT; + + return $tpl; + } + +} diff --git a/Controller/GraphQLController.php b/Controller/GraphQLController.php index 174f427..57955e1 100644 --- a/Controller/GraphQLController.php +++ b/Controller/GraphQLController.php @@ -10,27 +10,27 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; +use Youshido\GraphQL\Validator\Exception\ConfigurationException; class GraphQLController extends Controller { /** - * @param Request $request + * @Route("/graphql") * + * @throws ConfigurationException * @return JsonResponse - * - * @Route("/graphql") */ - public function apiAction(Request $request) + public function defaultAction() { + $request = $this->get('request_stack')->getCurrentRequest(); $query = $request->get('query', null); $variables = $request->get('variables', null); $variables = json_decode($variables, true) ?: []; - $content = $this->get("request")->getContent(); + $content = $request->getContent(); if (!empty($content)) { $params = json_decode($content, true); @@ -41,8 +41,13 @@ public function apiAction(Request $request) } $processor = $this->get('youshido.graphql.processor'); - - $processor->processQuery($query, $variables); + if ($schemaClass = $this->getParameter('youshido.graphql.schema_class')) { + if (!class_exists($schemaClass)) { + throw new ConfigurationException('Schema class ' . $schemaClass . ' does not exist'); + } + $processor->setSchema(new $schemaClass()); + } + $processor->processRequest($query, $variables); return new JsonResponse($processor->getResponseData(), 200, $this->getParameter('youshido.graphql.response_headers')); } diff --git a/DependencyInjection/GraphQLExtension.php b/DependencyInjection/GraphQLExtension.php index 150d581..17504b2 100644 --- a/DependencyInjection/GraphQLExtension.php +++ b/DependencyInjection/GraphQLExtension.php @@ -14,26 +14,39 @@ */ class GraphQLExtension extends Extension { + private $config = []; + /** * {@inheritdoc} */ public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); - $config = $this->processConfiguration($configuration, $configs); + $this->config = $this->processConfiguration($configuration, $configs); $responseHeaders = []; - if (isset($config['response_headers']) && is_array($config['response_headers'])) { - foreach ($config['response_headers'] as $responseHeader) { - $responseHeaders[$responseHeader['name']] = $responseHeader['value']; - } + foreach ($this->getConfig('response_headers', $this->getDefaultHeaders()) as $responseHeader) { + $responseHeaders[$responseHeader['name']] = $responseHeader['value']; } - $container->setParameter('youshido.graphql.project_schema', $config['query_schema']); + $container->setParameter('youshido.graphql.project_schema', $this->getConfig('query_schema', null)); $container->setParameter('youshido.graphql.response_headers', $responseHeaders); - $container->setParameter('youshido.graphql.logger', isset($config['logger']) ? $config['logger'] : null); + $container->setParameter('youshido.graphql.logger', $this->getConfig('logger', null)); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yml'); } + + private function getDefaultHeaders() + { + return [ + ['name' => 'Access-Control-Allow-Origin', 'value' => '*'], + ]; + } + + private function getConfig($key, $default = null) + { + return array_key_exists($key, $this->config) ? $this->config[$key] : $default; + } + } diff --git a/Processor/Processor.php b/Processor/Processor.php index 0413da1..f6c6919 100644 --- a/Processor/Processor.php +++ b/Processor/Processor.php @@ -30,13 +30,13 @@ public function setContainer(ContainerInterface $container = null) $this->container = $container; } - public function processQuery($queryString, $variables = []) + public function processRequest($queryString, $variables = []) { if ($this->logger) { $this->logger->debug(sprintf('GraphQL query: %s', $queryString), (array) $variables); } - parent::processQuery($queryString, $variables); + parent::processRequest($queryString, $variables); } /** diff --git a/README.md b/README.md index fdc6958..d00e989 100644 --- a/README.md +++ b/README.md @@ -14,24 +14,58 @@ This bundle provides you with: ## Installing GraphQL Bundle We assume you have `composer`, but if you're not – install it from the [official website](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx). -After you've done with that, simply run -``` -$> composer require youshido/graphql-bundle +Once you have your composer up and running – you're ready to install the GraphQL Bundle +```sh +composer require youshido/graphql-bundle ``` -Than add bundle to your `app/AppKernel.php` -``` -... +Than enable bundle in your `app/AppKernel.php` +```php new Youshido\GraphQLBundle\GraphQLBundle(), -... ``` -And finally add the routing reference to the `app/config/routing.yml`: -``` +Add the routing reference to the `app/config/routing.yml`: +```yaml graphql: resource: "@GraphQLBundle/Controller/" ``` +Let's check if you've done everything right so far – try to access the `localhost:8000/graphql` url. +You should get a JSON response with the following error: +```js +{"errors":[{"message":"You have to set GraphQL Schema to process"}]} +``` + +That's because there was no GraphQL Schema specified for the processor yet. +You need to create a GraphQL Schema class and set it inside your `app/config/config.yml` file. + +> THere is a way where you can use inline approach, in order to do that you have to define your own GraphQL controller and use a `->setSchema` method of the processor to set the Schema + +The fastest way to create a Schema class is to use a generator shipped with this bundle: +```sh +php bin/console graphql:schema:generate App +``` +Here *App* is a name of the bundle where the class will be generated in. +You will be requested for a confirmation to create a class and then presented with instructions to update your config file. + +```sh +Update your app/config/config.yml with the parameter: +graph_ql: + schema_class: AppBundle\GraphQL\Schema +``` + +After you've added parameters to config file, try to access the following link in the browser – 'http://localhost:8000/graphql?query={hello}' + +> Alternatively, you can execute the same request using CURL client in your console +> `curl http://localhost:8000/graphql --data "query={ hello }"` + +Successful response from a test Schema will be displayed: +```js +{"data":{"hello":"world!"}} +``` + +That means you have GraphQL Bundle for the Symfony Framework configured and now can architect your GraphQL Schema: + ## Documentation Detailed documentation is available on the main GraphQL repository – http://github.com/youshido/graphql/. diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 8c9ff2b..a6f0edf 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,12 +1,10 @@ parameters: youshido.graphql.processor.class: Youshido\GraphQLBundle\Processor\Processor - youshido.graphql.validator.class: Youshido\GraphQL\Validator\ResolveValidator\ResolveValidator services: youshido.graphql.processor: class: %youshido.graphql.processor.class% - arguments: [ @youshido.graphql.validator ] calls: - [ setSchema, [@youshido.graphql.schema]] - [ setContainer, [@service_container]] @@ -15,6 +13,3 @@ services: youshido.graphql.schema: class: %youshido.graphql.project_schema% - - youshido.graphql.validator: - class: %youshido.graphql.validator.class% \ No newline at end of file