From c65d8d8624c96756767ebabd7511e3ed90bff8ff Mon Sep 17 00:00:00 2001 From: Vladimir Razuvaev Date: Thu, 17 Aug 2017 20:35:35 +0700 Subject: [PATCH] Documented lazy loading of types in schema and ability to define schema using GraphQL type language --- docs/type-system/schema.md | 81 +++++++++++++++++++++++++++++ docs/type-system/type-language.md | 86 +++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 docs/type-system/type-language.md diff --git a/docs/type-system/schema.md b/docs/type-system/schema.md index 7c84440..62249c7 100644 --- a/docs/type-system/schema.md +++ b/docs/type-system/schema.md @@ -88,3 +88,84 @@ mutation | `ObjectType` | Object type (usually named "Mutation") containing subscription | `ObjectType` | Reserved for future subscriptions implementation. Currently presented for compatibility with introspection query of **graphql-js**, used by various clients (like Relay or GraphiQL) directives | `Directive[]` | Full list of [directives](directives/) supported by your schema. By default contains built-in `@skip` and `@include` directives.

If you pass your own directives and still want to use built-in directives - add them explicitly. For example: `array_merge(GraphQL::getInternalDirectives(), [$myCustomDirective]` types | `ObjectType[]` | List of object types which cannot be detected by **graphql-php** during static schema analysis.

Most often it happens when object type is never referenced in fields directly, but is still a part of schema because it implements an interface which resolves to this object type in it's `resolveType` callback.

Note that you are not required to pass all of your types here - it is simply a workaround for concrete use-case. + +# Lazy loading of types +By default a schema will scan all of your type and field definitions to serve GraphQL queries. +It may cause performance overhead when there are many types in a schema. + +In this case it is recommended to pass **typeLoader** option to schema constructor and define all +of your object **fields** as callbacks. + +Type loading concept is very similar to PHP class loading, but keep in mind that **typeLoader** must +always return the same instance of a type. + +Usage example: +```php +class Types +{ + private $registry = []; + + public function get($name) + { + if (!isset($this->types[$name])) { + $this->types[$name] = $this->{$name}(); + } + return $this->types[$name]; + } + + private function MyTypeA() + { + return new ObjectType([ + 'name' => 'MyTypeA', + 'fields' => function() { + return [ + 'b' => ['type' => $this->get('MyTypeB')] + ]; + } + ]); + } + + private function MyTypeB() + { + // ... + } +} + +$registry = new Types(); + +$schema = new Schema([ + 'query' => $registry->get('Query'), + 'typeLoader' => function($name) use ($registry) { + return $registry->get($name); + } +]); +``` + + +# Schema Validation +By default schema is created with only shallow validation of type and field definitions +(because validation requires full schema scan and is very costly on bigger schemas). + +But there is a special method `$schema->assertValid()` which throws `GraphQL\Error\InvariantViolation` +exception when it encounters any error, like: + +- Invalid types used for fields / arguments +- Missing interface implementations +- Invalid interface implementations +- Other schema errors... + +Schema validation is supposed to be used in CLI commands or during build step of your app. +Don't call it in web requests in production. + +Usage example: +```php +$schema = new GraphQL\Type\Schema([ + 'query' => $myQueryType +]); + +try { + $schema->assertValid(); +} catch (GraphQL\Error\InvariantViolation $e) { + echo $e->getMessage(); +} +``` diff --git a/docs/type-system/type-language.md b/docs/type-system/type-language.md new file mode 100644 index 0000000..58cbf25 --- /dev/null +++ b/docs/type-system/type-language.md @@ -0,0 +1,86 @@ +# Defining your schema + +[Type language](http://graphql.org/learn/schema/#type-language) is a convenient way to define your schema, +especially with IDE autocompletion and syntax validation. + +Here is a simple schema defined in GraphQL type language (e.g. in separate **schema.graphql** file): + +```graphql +schema { + query: Query + mutation: Mutation +} + +type Query { + greetings(input: HelloInput!): String! +} + +input HelloInput { + firstName: String! + lastName: String +} +``` + +In order to create schema instance out of this file, use `GraphQL\Utils\BuildSchema`: + +```php +toArray(), true)); +} else { + $document = Node::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well +} + +$typeConfigDecorator = function () {}; +$schema = BuildSchema::build($document, $typeConfigDecorator); +``` \ No newline at end of file