{"id":13652848,"url":"https://github.com/AmazeeLabs/graphql_directives","last_synced_at":"2025-04-23T03:31:33.246Z","repository":{"id":65190562,"uuid":"559486310","full_name":"AmazeeLabs/graphql_directives","owner":"AmazeeLabs","description":"Directive-based GraphQL schema implementation.","archived":false,"fork":false,"pushed_at":"2025-04-02T11:25:00.000Z","size":77,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-08T09:12:08.117Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AmazeeLabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-30T09:11:15.000Z","updated_at":"2025-04-02T11:25:04.000Z","dependencies_parsed_at":"2024-04-16T01:47:47.378Z","dependency_job_id":"df190314-04e2-4ae2-8387-305d16e56256","html_url":"https://github.com/AmazeeLabs/graphql_directives","commit_stats":{"total_commits":7,"total_committers":2,"mean_commits":3.5,"dds":0.1428571428571429,"last_synced_commit":"a5e38c2eddef807050731a21c7b8091db6ac4a5e"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmazeeLabs%2Fgraphql_directives","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmazeeLabs%2Fgraphql_directives/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmazeeLabs%2Fgraphql_directives/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmazeeLabs%2Fgraphql_directives/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AmazeeLabs","download_url":"https://codeload.github.com/AmazeeLabs/graphql_directives/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250365618,"owners_count":21418715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T02:01:03.329Z","updated_at":"2025-04-23T03:31:33.238Z","avatar_url":"https://github.com/AmazeeLabs.png","language":"PHP","funding_links":[],"categories":["Drupal"],"sub_categories":["Drupal modules"],"readme":"# GraphQL Directives\n\nA directive-based approach to GraphQL schema implementations. Provides a\n'Directable' schema plugin that loads a GraphQL schema definition file and\nimplements it using directive plugins.\n\n## Usage\n\nCreate a GraphQL schema definition file, and annotate it with directives.\n\n```graphql\ntype Query {\n  hello: String @value(string: \"Hello world!\")\n}\n```\n\nConfigure a GraphQL server with the \"Directable\" schema plugin, and set the\nschema definition path to the created schema file.\n\nDirective definitions will be automatically prepended to the schema. To support\nIDE's with autocompletion and syntax checking, there is a `drush` command to\ngenerate a schema file with all directives and information where they are\nimplemented.\n\n```shell\ndrush graphql:directives \u003e\u003e directives.graphqls\n```\n\n### Chaining\n\nDirectives can be chained to combine reusable data producers. They are composed\nfrom left to right, meaning the output of the left directive is passed as parent\nvalue to its right neighbour.\n\n```graphql\ntype Query {\n  # This will emit \"three\".\n  list: String! @value(json: \"[\\\"one\\\", \\\"two\\\", \\\"three\\\"]\") @seek(pos: 2)\n}\n```\n\n### Mapping\n\nThe `@map` directive allows to map over the output of its left neighbour and\napply all directives on the right side to each item.\n\n```graphql\ntype Query {\n  # This will emit [\"a\", \"b\"].\n  map: [String!]!\n    @value(json: \"[{\\\"x\\\": \\\"a\\\"},{\\\"x\\\": \\\"b\\\"}]\")\n    @map\n    @prop(key: \"x\")\n}\n```\n\n### Default values\n\nSince Drupal's data structures can't guarantee integrity, the graphql schema\nwill enforce default values as much as possible. Whenever a type is used in a\nnon-nullable position (no `!` at the end ), it attempts to apply a default value\nif the value is `null`. The default value is determined by the type, e.g. `0`\nfor `Int`, `false` for `Boolean`, `\"\"` for `String` and `[]` for list types like\n`[String!]!`.\n\nFor custom types, interface, unions or scalars, the `@default` directive can be\nused to start a directive chain that generates a default value.\n\n```graphql\nscalar MyScalar @default @value(string: \"bar\")\n\ntype Query {\n  # This will emit `''`.\n  string: String! @value\n  # This will emit `0`.\n  int: Int! @value\n  # This will emit `[]`.\n  list: [String!]! @value\n  # This will emit `bar`\n  manual: MyScalar! @value\n}\n```\n\n### Type resolution\n\nDirectives can also be used to resolve the runtime types of unions and\ninterfaces. To do that, apply any directives that can be used to resolve field\nvalues to the interface or union. The chain of directives should resolve to a\nstring value which will be treated as a type id.\n\n```graphql\nunion Letters @prop(key: \"type\") = A | B\n```\n\nThis resolved type id will then be matched against object types annotated with\nthe `@type` directive to retrieve the actual type.\n\n```graphql\ntype A @type(id: \"a\") {\n  type: String!\n}\n\ntype B @type(id: \"b\") {\n  type: String!\n}\n```\n\n## Argument handling\n\nDirectives can use the `ArgumentTrait` to apply dynamic arguments. If the\ndirective argument equals `$`, the current value will be passed as the argument\nvalue. If its `$`, followed by any characters, these characters will be used as\na key to retrieve the value from the current query arguments.\n\nArguments that implement this behaviour are marked to be (dynamic).\n\n```graphql\ntype Query {\n  static: Post @loadEntity(type: \"node\", id: \"1\")\n  parent: Post @value(int: 1) @loadEntity(type: \"node\", id: \"$\")\n  argument(id: String!): Post @loadEntity(type: \"node\", id: \"$id\")\n}\n```\n\n## Directives\n\n### `@value`\n\nThe `@value` directive allows you to define a static value for a field as\nprimitive or a JSON encoded string. Without any arguments, it will emit `null`.\n\n```graphql\ntype Query {\n  null: String @value\n  hello: String! @value(string: \"Hello world!\")\n  theAnswer: Int! @value(int: 42)\n  pi: Float! @value(float: 3.14)\n  true: Boolean! @value(float: true)\n  object: MyType! @value(json: \"{\\\"foo\\\":\\\"bar\\\"}\")\n}\n```\n\n### `@seek`\n\nExtracts a value from a list or iterable. The `pos` argument marks the target\nposition.\n\n```graphql\ntype Query {\n  # This will emit \"three\".\n  list: String! @value(json: \"[\\\"one\\\", \\\"two\\\", \\\"three\\\"]\") @seek(pos: 2)\n}\n```\n\n### `@prop`\n\nExtracts a property from an object or map. The `key` argument marks the target\nkey.\n\n```graphql\ntype Query {\n  # This will emit \"bar\".\n  prop: String! @value(json: \"{\\\"foo\\\": \\\"bar\\\"}\") @prop(key: \"foo\")\n}\n```\n\n### `@map`\n\nIterate over the current result list and apply the following directives to each\nitem.\n\n```graphql\ntype Query {\n  # This will emit [\"a\", \"b\"].\n  map: [String!]!\n    @value(json: \"[{\\\"x\\\": \\\"a\\\"},{\\\"x\\\": \\\"b\\\"}]\")\n    @map\n    @prop(key: \"x\")\n}\n```\n\n### `@type`\n\nAnnotate an object type with a specific id that will be used for interface- and\nunion type resolution.\n\n```graphql\nunion Letters @prop(key: \"type\") = A | B\n\ntype A @type(id: \"a\") {\n  type: String!\n}\n\ntype B @type(id: \"b\") {\n  type: String!\n}\n```\n\n### `@arg`\n\nRetrieve an arguments value and inject it as the current value that will be\npassed as parent to subsequent directives.\n\n```graphql\ntype Query {\n  post(path: String!): Page @arg(name: \"path\") @route(path: \"$\") @loadEntity\n}\n```\n\n### `@route`\n\nResolve a path (dynamic) to a Drupal `Url` object.\n\n```graphql\ntype Query {\n  post(path: String!): Page @route(path: \"$path\") @loadEntity\n}\n```\n\n### `@loadEntity`\n\nLoad Drupal entities in various ways. If there are no arguments, it assumes that\nthe parent value contains a `Url` object generated by `@route`, and it attempts\nto load the entity from there.\n\nIf used with `id ` or `uuid`, an optional `operation` argument allows to define\na specific operation for access checks.\n\n```graphql\ntype Query {\n  post(path: String!): Page @route(path: \"$path\") @loadEntity\n}\n```\n\nOtherwise, it requires to define a static `type` argument and either an `id`\n(dynamic) or `uuid` (dynamic) argument.\n\n```graphql\ntype Query {\n  id(id: String!): Post @loadEntity(type: \"node\", id: \"$id\")\n  uuid(uuid: String!): Post @loadEntity(type: \"node\", uuid: \"$uuid\")\n}\n```\n\n### `@resolveEntity[...]`\n\nRetrieve various simple properties of an entity. The following directives are\nsupported:\n\n- `@resolveEntityId`\n- `@resolveEntityUuid`\n- `@resolveEntityType`\n- `@resolveEntityBundle`\n- `@resolveEntityLabel`\n- `@resolveEntityPath`\n- `@resolveEntityLanguage`\n\n```graphql\ntype Query {\n  post(id: String!): Post @loadEntity(type: \"node\", id: \"$id\")\n}\n\ntype Post {\n  title: String! @resolveEntityLabel\n}\n```\n\n### `@resolveEntityTranslation`\n\nRetrieve as specific translation of an entity, defined by the `lang` (dynamic)\nargument.\n\n```graphql\ntype Query {\n  post(id: String!, lang: String!): Post\n    @loadEntity(type: \"node\", id: \"$id\")\n    @resolveEntityTranslation(lang: \"$lang\")\n}\n```\n\n### `@resolveEntityTranslations`\n\nRetrieve all translations of an entity.\n\n```graphql\ntype Query {\n  post(id: String!): Post @loadEntity(type: \"node\", id: \"$id\")\n}\n\ntype Post {\n  translations: [Post!]! @resolveEntityTranslations\n}\n```\n\n### `@resolveProperty`\n\nRetrieve a property of an entity by its `path` argument.\n\n```graphql\ntype Post {\n  body: String @resolveProperty(path: \"body.value\")\n}\n```\n\n### `@lang`\n\nSwitch the current execution language for the remaining subtree below the\ncurrent field. Accepts either a `code` argument (dynamic) or, if omitted, uses\nthe parent value. If the latter is a string, it will be used as-is, if its an\ninstance of `TranslatableInteface`, the language is derived from there.\n\n```graphql\ntype Query {\n  post(id: String!): Post @loadEntity(type: \"node\", id: \"$id\") @lang\n}\n```\n\n### `@resolveMenuItems`\n\nRetrieve all items of a menu entity. Accepts an optional `max_level` argument\nthat caps the maximum number of menu levels. The tree is flattened to a list, to\navoid the necessity of nested fragments. The `@resolveMenuItemId` and\n`@resolveMenuItemParentId` directives should be used to reconstruct the tree in\nthe consumer. The list of menu items is also filtered by language, respecting\nthe current execution context language, as it can be controlled by `@lang`.\n\n```graphql\ntype Query {\n  menu: Limited! @loadEntity(type: \"menu\", id: \"main\", operation: \"view label\")\n}\n\ntype Menu {\n  items: [MenuItem!]! @lang(code: \"fr\") @resolveMenuItems(max_level: 2)\n}\n```\n\n### `@resolveMenuItem[...]`\n\nVarious menu item properties.\n\n- `@resolveMenuItemId`\n- `@resolveMenuItemParentId`\n- `@resolveMenuItemLabel`\n- `@resolveMenuItemUrl`\n\n### `@resolveEntityReference` \u0026 `@resolveEntityReferenceRevisions`\n\nResolve referenced entities attached to a given `field`. Will attempt to\nretrieve translations matching the current host entity.\n\n```graphql\ntype Query {\n  post(id: String!): Post @loadEntity(type: \"node\", id: \"$id\") @lang\n}\n\ntype Post {\n  title: String! @resolveEntityLabel\n  related: [Post!]! @resolveEntityReference(field: \"field_related\")\n}\n```\n\n### `@drupalView`\n\nExecutes a Drupal view.\n\n```graphql\ntype Query {\n  contentHub(locale: String!, args: String): ContentHubView!\n    @lang(code: \"$locale\")\n    @drupalView(id: \"content_hub:default\", args: \"$args\")\n}\n\ntype ContentHubView {\n  total: Int!\n  rows: [Post!]!\n  filters: ContentHubViewFilters!\n}\n\ntype ContentHubViewFilters {\n  tag: [ViewFilter!]!\n  category: [ViewFilter!]!\n}\n\ntype ViewFilter {\n  value: String!\n  label: String!\n}\n```\n\n#### `id` argument\n\nView ID and display separated by colon. Example: `content_hub:default`.\n\n#### `args` argument\n\nFilters, page number, etc. in query string format. Example:\n`page=1\u0026pageSize=9\u0026contextualFilters=40/12\u0026tag[]=1\u0026type=foo`\n\nReserved keys:\n\n- `page`: The page number. Starts from 1. Defaults to 1.\n- `pageSize`: The number of items per page. Defaults to 10.\n- `contextualFilters`: Contextual filter values, for example, `40/12/10`.\n\nThe rest of keys are taken as filters.\n\nArray values are allowed in the format of NPM `query-string` package with\n`arrayFormat` set to `bracket`, e.g. `tag[]=1\u0026tag[]=2`. Ensure that the view\nfilter Selection type is set to Dropdown not Autocomplete for entity references.\n\n#### Returning result\n\nThe structure of the result is the following:\n\n```ts\ntype Result = {\n  total: number;\n  items: [DrupalEntity];\n  filters: {\n    [filterKey: string]: Array\u003c{\n      value: string;\n      label: string;\n    }\u003e;\n  };\n};\n```\n\n#### Translations\n\nUse the `@lang` directive to set the language for the view. If the resulting\nentities have the chosen language, they will be returned in that language.\n\nIf the results have to be filtered by the language, use\n`Content: Translation language (= Interface text language selected for page)`\nfilter in the view.\n\n## Extending\n\nTo add custom directives, create a module and add new Plugins in the\n`src/Plugin/GraphQL/Directive` directory. The plugins \"id\" will be the handle to\ninvoke it in the schema, without the `@` prefix.\n\n```php\n\u003c?php\nnamespace Drupal\\my_directives\\Plugin\\GraphQL\\Directive;\n\nuse Drupal\\graphql_directives\\DirectiveInterface;\n\n/**\n* @Directive(\n*   id=\"echo\",\n*   description=\"Return the same string that you put in.\",\n*   arguments = {\n*     \"input\" = \"String!\",\n*   }\n* )\n */\nclass EchoDirective extends PluginBase implements DirectiveInterface {\n  /**\n   * {@inheritdoc}\n   */\n  public function buildResolver(\n    ResolverBuilder $builder,\n    array $arguments\n  ) : ResolverInterface {\n    return $builder-\u003efromValue($arguments['input']);\n  }\n}\n```\n\n## Autoloading\n\nThe\n[`@amazeelabs/codegen-autoloader`](https://github.com/AmazeeLabs/silverback-mono/blob/development/packages/npm/@amazeelabs/codegen-autoloader/README.md)\nprovides a convenient option to add new directives using the `drupal` mode. The\nresulting JSON file is compatible to this modules `Autoload registry`\nconfiguration option.\n\n## Schema Extensions\n\nThe module provides a `DirectableSchemaExtensionPluginBase` class that can be\nused to create schema extensions that react to directives in the parent schema\ndefinition. A schema extension plugin for the Drupal GraphQL module provides two\nschema definitions: one for the \"base\" schema and one for the actual extensions.\nIn case of directable schema extension, the base schema definition should\ncontain the directives while the extension schema defines the derived types and\nfields.\n\nFor a very simple example, please refer to the `graphql_directives_test` module.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmazeeLabs%2Fgraphql_directives","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAmazeeLabs%2Fgraphql_directives","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmazeeLabs%2Fgraphql_directives/lists"}