{"id":13550465,"url":"https://github.com/juancastillo0/leto","last_synced_at":"2025-04-19T16:11:46.955Z","repository":{"id":46010417,"uuid":"401361089","full_name":"juancastillo0/leto","owner":"juancastillo0","description":"Dart GraphQL server libraries. Utilities, code generator, examples and reference implementation.","archived":false,"fork":false,"pushed_at":"2024-06-20T22:56:12.000Z","size":14126,"stargazers_count":41,"open_issues_count":14,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T09:51:16.911Z","etag":null,"topics":["backend","dart","flutter","graphql","server"],"latest_commit_sha":null,"homepage":"https://juancastillo0.github.io/leto/","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/juancastillo0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-08-30T13:52:21.000Z","updated_at":"2024-09-12T03:10:54.000Z","dependencies_parsed_at":"2024-03-16T22:59:22.816Z","dependency_job_id":"7c9636ab-97f5-4223-8f01-6ba623ddb0a8","html_url":"https://github.com/juancastillo0/leto","commit_stats":{"total_commits":1244,"total_committers":8,"mean_commits":155.5,"dds":"0.21543408360128613","last_synced_commit":"3e7351f3d8f46f5a8024165300bf4e11e4318816"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juancastillo0%2Fleto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juancastillo0%2Fleto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juancastillo0%2Fleto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juancastillo0%2Fleto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/juancastillo0","download_url":"https://codeload.github.com/juancastillo0/leto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249734438,"owners_count":21317797,"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":["backend","dart","flutter","graphql","server"],"created_at":"2024-08-01T12:01:33.432Z","updated_at":"2025-04-19T16:11:46.879Z","avatar_url":"https://github.com/juancastillo0.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"![Logo](img/leto-logo-white.svg)\n\n\u003cdiv style=\"text-align: center\"\u003e\n\u003chr\u003e\n\u003ca href=\"https://pub.dartlang.org/packages/leto\"\u003e\n  \u003cimg src=\"https://img.shields.io/pub/v/leto.svg\" alt=\"Pub package\"\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://codecov.io/gh/juancastillo0/leto\"\u003e\n  \u003cimg src=\"https://codecov.io/gh/juancastillo0/leto/branch/main/graph/badge.svg?token=QJLQSCIJ42\" alt=\"Code coverage\"/\u003e\n\u003c/a\u003e\n\n\u003ca href='https://coveralls.io/github/juancastillo0/leto?branch=main'\u003e\n  \u003cimg src='https://coveralls.io/repos/github/juancastillo0/leto/badge.svg?branch=main' alt='Coverage Status' /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://github.com/juancastillo0/leto/actions/workflows/test.yaml\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/checks-status/juancastillo0/leto/main\" alt=\"CI checks\"/\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://github.com/juancastillo0/leto/actions/workflows/test.yaml\"\u003e\n  \u003cimg src=\"https://github.com/juancastillo0/leto/actions/workflows/test.yaml/badge.svg\"  alt=\"CI tests\"/\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://pub.dev/packages/lint\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/style-lint-4BC0F5.svg\" alt=\"Lint\" /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://github.com/juancastillo0/leto/blob/main/LICENSE\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"Leto is released under the MIT license.\" /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"#contributing\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\" alt=\"PRs welcome\" /\u003e\n\u003c/a\u003e\n\n\u003ca href=\"https://juancastillo0.github.io/leto/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/docs-docusaurus-blue\" alt=\"Docusaurus Documentation\" /\u003e\n\u003c/a\u003e\n\n\u003c/div\u003e\n\n# Leto - GraphQL Server \u003c!-- omit in toc --\u003e\n\nA complete implementation of the official\n[GraphQL specification](https://graphql.github.io/graphql-spec/June2018/)\nin the Dart programming language.\n\nInspired by [graphql-js](https://github.com/graphql/graphql-js), [async-graphql](https://github.com/async-graphql/async-graphql) and [type-graphql](https://github.com/MichalLytek/type-graphql). First version of the codebase was forked from [angel-graphql](https://github.com/angel-dart-archive/graphql). Many tests and utilities ([DataLoader](https://github.com/graphql/dataloader), [printSchema](https://github.com/graphql/graphql-js/blob/10c1c3d6cd8e165501fb1471b5babfabd1be1eb1/src/utilities/printSchema.ts)) were ported from graphql-js.\n\nIf your prefer to read the documentation in a web page, you can [try the documentation page](https://juancastillo0.github.io/leto/) built with Docusaurus.\n\n## Table of Contents\n- [Quickstart](#quickstart)\n  - [Install](#install)\n  - [Create a `GraphQLSchema`](#create-a-graphqlschema)\n    - [Using Code Generation](#using-code-generation)\n  - [Start the server](#start-the-server)\n  - [Test the server](#test-the-server)\n- [Examples](#examples)\n  - [Code Generator example](#code-generator-example)\n  - [Fullstack Dart Chat](#fullstack-dart-chat)\n    - [Chat functionalities](#chat-functionalities)\n  - [Server example](#server-example)\n  - [Room Signals](#room-signals)\n  - [CI \\\u0026 CD Dart Server](#ci--cd-dart-server)\n- [Packages](#packages)\n- [Web integrations](#web-integrations)\n  - [Server integrations](#server-integrations)\n    - [Shelf](#shelf)\n  - [Web UI Explorers](#web-ui-explorers)\n    - [GraphiQL](#graphiql)\n    - [Playground](#playground)\n    - [Altair](#altair)\n  - [Clients](#clients)\n- [Documentation](#documentation)\n- [GraphQL Schema Types](#graphql-schema-types)\n  - [Scalars](#scalars)\n  - [Enums](#enums)\n  - [Objects](#objects)\n    - [Interfaces](#interfaces)\n  - [Inputs and Input Objects](#inputs-and-input-objects)\n    - [InputObject.isOneOf](#inputobjectisoneof)\n    - [InputObject.fromJson](#inputobjectfromjson)\n  - [Unions](#unions)\n    - [Freezed Unions](#freezed-unions)\n  - [Wrapping Types](#wrapping-types)\n  - [Non-Nullable](#non-nullable)\n  - [Lists](#lists)\n  - [Abstract Types](#abstract-types)\n    - [resolveType](#resolvetype)\n    - [Generics](#generics)\n    - [isTypeOf](#istypeof)\n    - [\\_\\_typename](#__typename)\n    - [Serialize and validate](#serialize-and-validate)\n  - [Advanced Types](#advanced-types)\n    - [Provided Types](#provided-types)\n    - [Cyclic Types](#cyclic-types)\n    - [Custom Scalars](#custom-scalars)\n    - [Generic Types](#generic-types)\n- [Resolvers](#resolvers)\n  - [Queries and Mutations](#queries-and-mutations)\n  - [Subscriptions](#subscriptions)\n    - [Examples](#examples-1)\n  - [Request Contexts](#request-contexts)\n    - [Ctx](#ctx)\n    - [ObjectExecutionCtx](#objectexecutionctx)\n    - [ExecutionCtx](#executionctx)\n    - [RequestCtx](#requestctx)\n- [Validation](#validation)\n  - [Schema Validation](#schema-validation)\n  - [Document Validation](#document-validation)\n  - [Query Complexity](#query-complexity)\n  - [Skip validation with Persisted Queries](#skip-validation-with-persisted-queries)\n  - [Input Validation](#input-validation)\n- [Miscellaneous](#miscellaneous)\n  - [`GraphQLResult`](#graphqlresult)\n  - [`ScopedMap`](#scopedmap)\n    - [`ScopedHolder`](#scopedholder)\n    - [`ScopedRef`](#scopedref)\n    - [Example usage](#example-usage)\n  - [Error Handling](#error-handling)\n    - [Exceptions and `GraphQLError`](#exceptions-and-graphqlerror)\n    - [Result types](#result-types)\n    - [Error lists and interfaces](#error-lists-and-interfaces)\n  - [Hot Reload and Cycles](#hot-reload-and-cycles)\n- [Solving the N+1 problem](#solving-the-n1-problem)\n  - [LookAhead (Eager loading)](#lookahead-eager-loading)\n  - [DataLoader (Batching)](#dataloader-batching)\n  - [Combining LookAhead with DataLoader](#combining-lookahead-with-dataloader)\n- [Extensions](#extensions)\n  - [Persisted Queries](#persisted-queries)\n  - [Apollo Tracing](#apollo-tracing)\n  - [Response Cache](#response-cache)\n  - [Logging Extension](#logging-extension)\n  - [Map Error Extension](#map-error-extension)\n  - [Custom Extensions](#custom-extensions)\n- [Directives](#directives)\n  - [`KeyDirective`](#keydirective)\n  - [`ValidaDirective`](#validadirective)\n- [Attachments](#attachments)\n  - [AttachmentWithValidation](#attachmentwithvalidation)\n  - [ToDirectiveValue](#todirectivevalue)\n    - [`KeyAttachment`](#keyattachment)\n    - [`ValidaAttachment`](#validaattachment)\n  - [Usage](#usage)\n    - [AttachFn for code generation](#attachfn-for-code-generation)\n- [Utilities](#utilities)\n    - [`buildSchema`](#buildschema)\n    - [`printSchema`](#printschema)\n    - [`extendSchema`](#extendschema)\n    - [`introspectionQuery`](#introspectionquery)\n    - [`mergeSchemas`](#mergeschemas)\n    - [`schemaFromJson`](#schemafromjson)\n- [Contributing](#contributing)\n  - [Scripts](#scripts)\n    - [`collect_examples.dart`](#collect_examplesdart)\n    - [`generate_docusaurus.dart`](#generate_docusaurusdart)\n\n# Quickstart\u003c!-- docusaurus{\"tags\":[\"tutorial\"]} --\u003e\n\nThis provides a simple introduction to Leto, you can explore more in the following sections of this README or by looking at the tests, documentation and examples for each package. A fullstack Dart example with Flutter client and Leto/Shelf server can be found in https://github.com/juancastillo0/leto/tree/main/chat_example\n\nThe source code for this quickstart can be found in https://github.com/juancastillo0/leto/blob/main/leto_shelf/example/lib/quickstart_server.dart.\n\n## Install\n\nAdd dependencies to your pubspec.yaml\n\n```yaml\ndependencies:\n  leto_schema: ^0.0.1-dev.3\n  leto: ^0.0.1-dev.1\n  leto_shelf: ^0.0.1-dev.1\n  shelf: ^1.0.0\n  shelf_router: ^1.0.0\n  # Not nessary for the server, just for testing it\n  http: ^1.0.0\n\ndev_dependencies:\n  # Only if you use code generation\n  leto_generator: ^0.0.1-dev.3\n  build_runner: ^2.0.0\n```\n\n## Create a `GraphQLSchema`\n\n\nSpecify the logic for your server, this could be anything such as accessing a database, reading a file or sending an http request. We will use a controller class with a stream that emits events on mutation to support subscriptions.\n\n\u003c!-- include{quickstart-controller-state-definition} --\u003e\n```dart\n// this annotations is only necessary for code generation\n@GraphQLObject()\nclass Model {\n  final String state;\n  final DateTime createdAt;\n\n  const Model(this.state, this.createdAt);\n}\n\n/// Set up your state.\n/// This could be anything such as a database connection.\n///\n/// Global means that there will only be one instance of [ModelController]\n/// for this reference. As opposed to [ScopedRef.local] where there will be\n/// one [ModelController] for each request (for saving user information\n/// or a [DataLoader], for example).\nfinal stateRef = ScopedRef\u003cModelController\u003e.global(\n  (scope) =\u003e ModelController(\n    Model('InitialState', DateTime.now()),\n  ),\n);\n\nclass ModelController {\n  Model? _value;\n  Model? get value =\u003e _value;\n\n  final _streamController = StreamController\u003cModel\u003e.broadcast();\n  Stream\u003cModel\u003e get stream =\u003e _streamController.stream;\n\n  ModelController(this._value);\n\n  void setValue(Model newValue) {\n    if (newValue.state == 'InvalidState') {\n      // This will appear as an GraphQLError in the response.\n      // You can pass more information using custom extensions.\n      throw GraphQLError(\n        \"Can't be in InvalidState.\",\n        extensions: {'errorCodeExtension': 'INVALID_STATE'},\n      );\n    }\n    _value = newValue;\n    _streamController.add(newValue);\n  }\n}\n```\n\u003c!-- include-end{quickstart-controller-state-definition} --\u003e\n\nWith the logic that you want to expose, you can create the GraphQLSchema instance and access the controller state using the `Ctx` for each resolver and the `ScopedRef.get` method. The following is a schema with Query, Mutation and Subscription with a simple model. However, GraphQL is a very expressive language with [Unions](#unions), [Enums](#enums), [complex Input Objects](#inputs-and-input-objects), [collections](#wrapping-types) and more. For more documentation on writing GraphQL Schemas with Leto you can read the following sections, tests and examples for each package.\n\nTo expose this logic, we could implement the following GraphQL API:\n\n\u003c!-- include{quickstart-schema-string} --\u003e\n```graphql\ntype Query {\n  \"\"\"Get the current state\"\"\"\n  getState: Model\n}\n\ntype Model {\n  state: String!\n  createdAt: Date!\n}\n\n\"\"\"An ISO-8601 Date.\"\"\"\nscalar Date\n\ntype Mutation {\n  setState(\n    \"\"\"The new state, can't be 'WrongState'!.\"\"\"\n    newState: String!\n  ): Boolean!\n}\n\ntype Subscription {\n  onStateChange: Model!\n}\n```\n\u003c!-- include-end{quickstart-schema-string} --\u003e\n\nThis could be exposed by using `package:leto_schema` API as shown in the following code sample or more simply by [using code generation](#using-code-generation).\n\n\u003c!-- include{quickstart-make-schema} --\u003e\n```dart\n/// Create a [GraphQLSchema].\n/// All of this can be generated automatically using `package:leto_generator`\nGraphQLSchema makeGraphQLSchema() {\n  // The [Model] GraphQL Object type. It will be used in the schema\n  final GraphQLObjectType\u003cModel\u003e modelGraphQLType = objectType\u003cModel\u003e(\n    'Model',\n    fields: [\n      // All the fields that you what to expose\n      graphQLString.nonNull().field(\n            'state',\n            resolve: (Model model, Ctx ctx) =\u003e model.state,\n          ),\n      graphQLDate.nonNull().field(\n            'createdAt',\n            resolve: (Model model, Ctx ctx) =\u003e model.createdAt,\n          ),\n    ],\n  );\n  // The executable schema. The `queryType`, `mutationType`\n  // and `subscriptionType` are should be GraphQL Object types\n  final schema = GraphQLSchema(\n    queryType: objectType('Query', fields: [\n      // Use the created [modelGraphQLType] as the return type for the\n      // \"getState\" root Query field\n      modelGraphQLType.field(\n        'getState',\n        description: 'Get the current state',\n        resolve: (Object? rootValue, Ctx ctx) =\u003e stateRef.get(ctx).value,\n      ),\n    ]),\n    mutationType: objectType('Mutation', fields: [\n      graphQLBoolean.nonNull().field(\n        'setState',\n        // set up the input field. could also be done with\n        // `graphQLString.nonNull().inputField('newState')`\n        inputs: [\n          GraphQLFieldInput(\n            'newState',\n            graphQLString.nonNull(),\n            description: \"The new state, can't be 'WrongState'!.\",\n          ),\n        ],\n        // execute the mutation\n        resolve: (Object? rootValue, Ctx ctx) {\n          final newState = ctx.args['newState']! as String;\n          if (newState == 'WrongState') {\n            return false;\n          }\n          stateRef.get(ctx).setValue(Model(newState, DateTime.now()));\n          return true;\n        },\n      ),\n    ]),\n    subscriptionType: objectType('Subscription', fields: [\n      // The Subscriptions are the same as Queries and Mutations as above,\n      // but should use `subscribe` instead of `resolve` and return a `Steam`\n      modelGraphQLType.nonNull().field(\n            'onStateChange',\n            subscribe: (Object? rootValue, Ctx ctx) =\u003e stateRef.get(ctx).stream,\n          )\n    ]),\n  );\n  assert(schema.schemaStr == schemaString.trim());\n  return schema;\n}\n\n```\n\u003c!-- include-end{quickstart-make-schema} --\u003e\n\n### Using Code Generation\n\nYou can use code generation to create a function similar to `makeGraphQLSchema` with the following resolver definitions with annotations.\n\n\u003c!-- include{quickstart-make-schema-code-gen} --\u003e\n```dart\n/// Code Generation\n/// Using leto_generator, [makeGraphQLSchema] could be generated\n/// with the following annotated functions and the [GraphQLObject]\n/// annotation over [Model]\n\n/// Get the current state\n@Query()\nModel? getState(Ctx ctx) {\n  return stateRef.get(ctx).value;\n}\n\n@Mutation()\nbool setState(\n  Ctx ctx,\n  // The new state, can't be 'WrongState'!.\n  String newState,\n) {\n  if (newState == 'WrongState') {\n    return false;\n  }\n\n  stateRef.get(ctx).setValue(Model(newState, DateTime.now()));\n  return true;\n}\n\n@Subscription()\nStream\u003cModel\u003e onStateChange(Ctx ctx) {\n  return stateRef.get(ctx).stream;\n}\n```\n\u003c!-- include-end{quickstart-make-schema-code-gen} --\u003e\n\nThis generates the same `modelGraphQLType` in `\u003cfile\u003e.g.dart` and `graphqlApiSchema` in 'lib/graphql_api.schema.dart' (TODO: 1G configurable). The documentation comments will be used as description in the generated schema. More information on code generation can be found in the following sections, in the `package:leto_generator`'s [README](https://github.com/juancastillo0/leto/tree/main/leto_generator) or in the code generation [example](https://github.com/juancastillo0/leto/tree/main/leto_generator/example).\n\n## Start the server\n\nWith the `GraphQLSchema` and the resolver logic implemented, we can set up the shelf handlers for each route. In this case we will use the `graphQLHttp` handlers for the \"/graphql\" endpoint and `graphQLWebSocket` for \"/graphql-subscription\" which supports subscriptions. You could provide custom extensions, document validations or a `ScopedMap` to override the state in the `GraphQL` executor constructor.\n\n\u003c!-- include{quickstart-setup-graphql-server} --\u003e\n```dart\nFuture\u003cHttpServer\u003e runServer({int? serverPort, ScopedMap? globals}) async {\n  // you can override state with ScopedMap.setGlobal/setScoped\n  final ScopedMap scopedMap = globals ?? ScopedMap();\n  if (globals == null) {\n    // if it wasn't overridden it should be the default\n    assert(stateRef.get(scopedMap).value?.state == 'InitialState');\n  }\n  // Instantiate the GraphQLSchema\n  final schema = makeGraphQLSchema();\n  // Instantiate the GraphQL executor, you can pass extensions and\n  // decide whether you want to introspect the schema\n  // and validate the requests\n  final letoGraphQL = GraphQL(\n    schema,\n    extensions: [],\n    introspect: true,\n    globalVariables: scopedMap,\n  );\n\n  final port =\n      serverPort ?? const int.fromEnvironment('PORT', defaultValue: 8080);\n  const graphqlPath = 'graphql';\n  const graphqlSubscriptionPath = 'graphql-subscription';\n  final endpoint = 'http://localhost:$port/$graphqlPath';\n  final subscriptionEndpoint = 'ws://localhost:$port/$graphqlSubscriptionPath';\n\n  // Setup server endpoints\n  final app = Router();\n  // GraphQL HTTP handler\n  app.all(\n    '/$graphqlPath',\n    graphQLHttp(letoGraphQL),\n  );\n  // GraphQL WebSocket handler\n  app.all(\n    '/$graphqlSubscriptionPath',\n    graphQLWebSocket(\n      letoGraphQL,\n      pingInterval: const Duration(seconds: 10),\n      validateIncomingConnection: (\n        Map\u003cString, Object?\u003e? initialPayload,\n        GraphQLWebSocketShelfServer wsServer,\n      ) {\n        if (initialPayload != null) {\n          // you can authenticated an user with the initialPayload:\n          // final token = initialPayload['token']! as String;\n          // ...\n        }\n        return true;\n      },\n    ),\n  );\n```\n\u003c!-- include-end{quickstart-setup-graphql-server} --\u003e\n\nIn the shelf router you can specify other handlers such as static files or other utilities. In the following code we set up a [GraphQL UI explorer](#web-ui-explorers) in the \"/playground\" route using the `playgroundHandler` handler and a \"/graphql-schema\" endpoint that returns the GraphQL schema String in the body of the response.\n\n\u003c!-- include{quickstart-setup-graphql-server-utilities} --\u003e\n```dart\n  // GraphQL schema and endpoint explorer web UI.\n  // Available UI handlers: playgroundHandler, graphiqlHandler and altairHandler\n  app.get(\n    '/playground',\n    playgroundHandler(\n      config: PlaygroundConfig(\n        endpoint: endpoint,\n        subscriptionEndpoint: subscriptionEndpoint,\n      ),\n    ),\n  );\n  // Simple endpoint to download the GraphQLSchema as a SDL file.\n  // $ curl http://localhost:8080/graphql-schema \u003e schema.graphql\n  const downloadSchemaOnOpen = true;\n  const schemaFilename = 'schema.graphql';\n  app.get('/graphql-schema', (Request request) {\n    return Response.ok(\n      schema.schemaStr,\n      headers: {\n        'content-type': 'text/plain',\n        'content-disposition': downloadSchemaOnOpen\n            ? 'attachment; filename=\"$schemaFilename\"'\n            : 'inline',\n      },\n    );\n  });\n```\n\u003c!-- include-end{quickstart-setup-graphql-server-utilities} --\u003e\n\nOnce you set up all the handlers, you can start the server adding middlewares if necessary. In this example, we will use the `etag` and `cors` middlewares from `package:leto_shelf`. You can read more about them in the [package's README](https://github.com/juancastillo0/leto/tree/main/leto_shelf).\n\n\u003c!-- include{quickstart-start-server} --\u003e\n```dart\n  // Set up other shelf handlers such as static files\n\n  // Start the server\n  final server = await shelf_io.serve(\n    const Pipeline()\n        // Configure middlewares\n        .addMiddleware(customLog(log: (msg) {\n          // TODO: 2A detect an introspection query.\n          //  Add more structured logs and headers\n          if (!msg.contains('IntrospectionQuery')) {\n            print(msg);\n          }\n        }))\n        .addMiddleware(cors())\n        .addMiddleware(etag())\n        .addMiddleware(jsonParse())\n        // Add Router handler\n        .addHandler(app),\n    '0.0.0.0',\n    port,\n  );\n  print(\n    'GraphQL Endpoint at $endpoint\\n'\n    'GraphQL Subscriptions at $subscriptionEndpoint\\n'\n    'GraphQL Playground UI at http://localhost:$port/playground',\n  );\n\n  return server;\n}\n```\n\u003c!-- include-end{quickstart-start-server} --\u003e\n\nWith the `runServer` function finished, we can now create a main function that executes it and servers the implemented logic in a GraphQL server. This function can also be used for test as shown in the `testServer` function from the next section. \n\n\u003c!-- include{quickstart-main-fn} --\u003e\n```dart\nFuture\u003cvoid\u003e main() async {\n  final server = await runServer();\n  final url = Uri.parse('http://${server.address.host}:${server.port}/graphql');\n  await testServer(url);\n}\n```\n\u003c!-- include-end{quickstart-main-fn} --\u003e\n\n## Test the server\n\nYou can test the server programmatically by sending HTTP requests to the server. You could also test the GraphQL executor directly using the `GraphQL.parseAndExecute` function without running the shelf server.\n\n\u003c!-- include{quickstart-test-server} --\u003e\n```dart\n/// For a complete GraphQL client you probably want to use\n/// Ferry (https://github.com/gql-dart/ferry)\n/// Artemis (https://github.com/comigor/artemis)\n/// or raw GQL Links (https://github.com/gql-dart/gql/tree/master/links)\nFuture\u003cvoid\u003e testServer(Uri url) async {\n  final before = DateTime.now();\n  const newState = 'NewState';\n  // POST request which sets the state\n  final response = await http.post(\n    url,\n    body: jsonEncode({\n      'query':\n          r'mutation setState ($state: String!) { setState(newState: $state) }',\n      'variables': {'state': newState}\n    }),\n    headers: {'content-type': 'application/json'},\n  );\n  assert(response.statusCode == 200);\n  final body = jsonDecode(response.body) as Map\u003cString, Object?\u003e;\n  final data = body['data']! as Map\u003cString, Object?\u003e;\n  assert(data['setState'] == true);\n\n  // Also works with GET\n  final responseGet = await http.get(url.replace(\n    queryParameters: \u003cString, String\u003e{\n      'query': '{ getState { state createdAt } }'\n    },\n  ));\n  assert(responseGet.statusCode == 200);\n  final bodyGet = jsonDecode(responseGet.body) as Map\u003cString, Object?\u003e;\n  final dataGet = bodyGet['data']! as Map\u003cString, dynamic\u003e;\n  assert(dataGet['getState']['state'] == newState);\n  final createdAt = DateTime.parse(dataGet['getState']['createdAt'] as String);\n  assert(createdAt.isAfter(before));\n  assert(createdAt.isBefore(DateTime.now()));\n\n  // To test subscriptions you can open the playground web UI at /playground\n  // or programmatically using https://github.com/gql-dart/gql/tree/master/links/gql_websocket_link,\n  // an example can be found in test/mutation_and_subscription_test.dart\n}\n```\n\u003c!-- include-end{quickstart-test-server} --\u003e\n\nTest and explore the server manually in the explorer interface \"http://localhost:8080/playground\". It supports subscriptions, subscribe in one tab and send a mutation request in another to test it. There are other UI explorers that you can set up (for example, GraphiQL and Altair), for more information [Web UI explorers section](#web-ui-explorers).\n\nWe also set up a \"http://localhost:8080/graphql-schema\" endpoint which returns the GraphQL schema String in the schema definition language, this could be useful for other tools such as client side code generators.\n\n# Examples\n\nBeside the tests from each package, you can find some usage example in the following directories and external repositories:\n\n\n## Code Generator example\n\nAn example with multiple ways of creating a GraphQLSchema with different GraphQL types and resolvers from code generation can be found in https://github.com/juancastillo0/leto/tree/main/leto_generator/example.\n\n\n## Fullstack Dart Chat\n\nA fullstack Dart example with Flutter client and Leto/Shelf server can be found in https://github.com/juancastillo0/leto/tree/main/chat_example. The server is in the [server](https://github.com/juancastillo0/leto/tree/main/chat_example/server) folder.\n\n- Sqlite3 and Postgres database integrations\n- Subscriptions\n- Authentication/Authorization\n- Sessions\n- Tests\n- File uploads\n- Client/Server GraphQL extensions integration\n- Docker\n\n### Chat functionalities\n\n- Send/receive/delete messages in realtime\n  - File uploads\n  - Link metadata\n  - Reply to other messages\n- Client cache through [Ferry](https://github.com/gql-dart/ferry) and [Hive](https://github.com/hivedb/hive)\n- Create chat rooms, add/remove users and share authorized invite links\n- View complete usage history with events for the most important mutations\n- View all user sessions\n\n## Server example\n\nA Leto/Shelf server example with multiple models, code generation, some utilities and tests can be found in https://github.com/juancastillo0/leto/tree/main/leto_shelf/example\n\n## Room Signals\n\nA service with room and messages, an user can subscribe to a room to listen to messages and send private or group-wide messages. Useful for simple messages or setting up peer-to-peer protocols like WebRTC. The service uses web sockets and in the source code repository there are three projects:\n\n1. The Leto Shelf GraphQL server. Everything is saved in memory\n2. A Dart client using [Artemis](https://github.com/comigor/artemis)\n3. A Web Dart client using [`package:rad`](https://github.com/erlage/rad)\n\nYou can view the code in the [Github repo](https://github.com/juancastillo0/room_signals). The client UI and some links to the different GraphQL Schema UI explorer is deployed in [this page](https://juancastillo0.github.io/room_signals/).\n\n## CI \u0026 CD Dart Server\n\nWork in Progress\n\nA service for compiling, executing and tracking the build process and deployment. With a git repository, one can set up a CLI pipeline for continuous integration and delivery. All the commands are tracked in realtime. This is a simple personal project for deploying in a VM. The service uses web sockets and the source code repository has three projects:\n\n1. The Leto Shelf GraphQL server. Everything is saved in memory\n2. A Dart client using [`package:graphql`](https://pub.dev/packages/graphql) and [`package:graphql_codegen`](https://pub.dev/packages/graphql_codegen)\n3. A Web Dart client using [`package:jaspr`](https://github.com/schultek/jaspr)\n\nYou can view the code in the [Github repo](https://github.com/juancastillo0/cidart). The client UI and some links to the different GraphQL Schema UI explorer is deployed in [this page](https://juancastillo0.github.io/cidart/).\n\n\n# Packages\n\nThis repository is a monorepo with the following packages\n\n| Pub                                                                                                    | Source                             | Description                                                                                |\n| ------------------------------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------ |\n| [![version](https://img.shields.io/pub/v/leto.svg)](https://pub.dev/packages/leto)                     | [leto](./leto)                     | GraphQL server (executor) implementation, GraphQL extensions and DataLoader                |\n| [![version](https://img.shields.io/pub/v/leto_schema.svg)](https://pub.dev/packages/leto_schema)       | [leto_schema](./leto_schema)       | Define GraphQL executable schemas, validate GraphQL documents and multiple utilities       |\n| [![version](https://img.shields.io/pub/v/leto_generator.svg)](https://pub.dev/packages/leto_generator) | [leto_generator](./leto_generator) | Generate GraphQL schemas, types and fields from Dart code annotations                      |\n| [![version](https://img.shields.io/pub/v/leto_shelf.svg)](https://pub.dev/packages/leto_shelf)         | [leto_shelf](./leto_shelf)         | GraphQL web server bindings and utilities for  [shelf](https://github.com/dart-lang/shelf) |\n| [![version](https://img.shields.io/pub/v/leto_links.svg)](https://pub.dev/packages/leto_links)         | [leto_links](./leto_links)         | Client gql links, support for GraphQL extensions defined in package:leto                   |\n\n# Web integrations\n\nAlthough you can use `package:leto_schema` to create and validate schemas and `package:leto` to execute GraphQL requests in any Dart application, GraphQL servers are usually deployed to the web. We provide a couple of utilities and integrations for creating and using GraphQL web servers powered by Leto.\n\n## Server integrations\n\n### [Shelf](https://github.com/juancastillo0/leto/tree/main/leto_shelf)\n\nUsing the [shelf](https://github.com/dart-lang/shelf) package.\n\n- [HTTP](https://graphql.org/learn/serving-over-http/) POST and GET\n- [Mutipart requests](https://github.com/jaydenseric/graphql-multipart-request-spec) for file Upload.\n- Subscriptions through WebSockets. Supporting [graphql-ws](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) and [graphql-transport-ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) subprotocols\n- Batched queries\n- TODO: HTTP/2 example\n- TODO: [Server-Sent Events](https://the-guild.dev/blog/graphql-over-sse)\n\n## Web UI Explorers\n\nThese web pages will allow you to explore your GraphQL Schema, view all the types and fields, read each element's documentation, and execute requests against a GraphQL server. \n\nUsually exposed as static HTML in your deployed server. Each has multiple configurations for determining the default tabs, queries and variables, the GraphQL HTTP and WebSocket (subscription) endpoints, the UI's theme and more.\n\nAll of the static HTML files and configurations can be found in the [graphql_ui folder](https://github.com/juancastillo0/leto/tree/main/leto_shelf/lib/src/graphql_ui).\n\n### GraphiQL\n\n[Documentation](https://github.com/graphql/graphiql/tree/main/packages/graphiql#readme). Use `graphiqlHandler`. The classic GraphQL explorer\n### Playground\n\n[Documentation](https://github.com/graphql/graphql-playground). Use `playgroundHandler`. Support for multiple tabs, subscriptions.\n### Altair\n\n[Documentation](https://github.com/altair-graphql/altair). Use `altairHandler`. Support for file Upload, multiple tabs, subscriptions, plugins.\n\n\n## Clients\n\nFor a complete GraphQL client you probably want to use:\n\n- Ferry (https://github.com/gql-dart/ferry)\n- Artemis (https://github.com/comigor/artemis)\n- `package:graphql` (https://pub.dev/packages/graphql) with `package:graphql_codegen` (https://pub.dev/packages/graphql_codegen)\n- or raw gql Links (https://github.com/gql-dart/gql/tree/master/links)\n  \n  gql Links are used by Ferry and Artemis, both of which provide additional functionalities over raw gql Links like serialization and deserialization, code generation, type safety, normalized caching and more.\n\n# Documentation\n\nThe following sections introduce most of the concepts and small examples of building GraphQL executable schemas and servers with Leto. Please, if there is something that may be missing from the documentation or you have any question you can make an issue, that would help us a lot.\n\nIf your prefer to read the documentation in a web page, you can [try the documentation page](https://juancastillo0.github.io/leto/) built with Docusaurus.\n\n# GraphQL Schema Types\u003c!-- docusaurus{\"global\":true} --\u003e\n\nThe GraphQL language provides multiple types for representing your exposed API and the required data structures for the input values. In the following sections we explain their usage within Leto and, in general, for GraphQL. Each section contains a link to the official GraphQL specification for more information.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Schema)\n\n## Scalars\n\nThe fundamental building-block in the type system. Standard `GraphQLScalarType`s: String, Int, Float, Boolean and ID types are already implemented and provided by Leto.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Scalars)\n\nOther scalar types are also provided:\n\n- Json: A raw JSON value with no type schema. Could be a Map\u003cString, Json\\\u003e, List\u003cJson\\\u003e, num, String, bool or null.\n- Uri: Dart's Uri class, serialized using `Uri.toString` and deserialized with `Uri.parse`\n- Date: Uses the `DateTime` Dart class. Serialized as an [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) String and deserialized with `DateTime.parse`.\n- Timestamp: Same as Date, but serialized as an UNIX timestamp.\n- Time: // TODO: 1A\n- Duration: // TODO: 1A\n- BigInt: An arbitrarily large integer from [`dart:core`](https://api.dart.dev/stable/dart-core/BigInt-class.html) serialized as a String and deserialized with `BigInt.parse`.\n- Upload: A file upload. Following the [multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec).\n\nTo provide your own or support types from other packages you can use [Custom Scalars](#custom-scalars).\n\n## Enums\n\nEnums are text values which are restricted to a set of predefined variants. Their behavior is similar to scalars and they don't have a nested fields.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Enums)\n\nThey require a unique name and a set of entries mapping their string representation to the Dart value obtained after parsing.\n\n```graphql\n\"\"\"The error reason on a failed sign up attempt\"\"\"\nenum SignUpError {\n    usernameTooShort,\n    usernameNotFound,\n    wrongPassword,\n    passwordTooSimple,\n}\n```\n\n```dart\nimport 'package:leto/leto.dart';\n\nfinal signUpErrorGraphQLType = enumTypeFromStrings(\n  'SignUpError', \n  [\n    'usernameTooShort',\n    'usernameNotFound',\n    'wrongPassword',\n    'passwordTooSimple',\n  ],\n  description: 'The error reason on a failed sign up attempt',\n);\n\n\n// Or with code generation\n\n/// The error reason on a failed sign up attempt\n@GraphQLEnum()\nenum SignUpError {\n    usernameTooShort,\n    usernameNotFound,\n    wrongPassword,\n    passwordTooSimple,\n}\n\n```\n## Objects\n\nGraphQL objects allow you to specify a type with a set of fields or properties. Objects can only be outputs in a resolver. Each field can be of any output type.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Objects)\n\nThe Query, Mutation and Subscription types in the schema are specified using GraphQL objects.\n\n```dart\nfinal type = objectType(\n  'ObjectTypeName',\n  fields: [],\n);\n```\n\n- With code generation\n\n```dart\n@GraphQLObject()\n@JsonSerializable()\nclass Model {\n  final String stringField;\n  final int intField;\n  final List\u003cModel\u003e? optionalModels;\n\n  const Model({\n    required this.stringField,\n    required this.intField,\n    required this.optionalModels,\n  });\n}\n\n@Query\nFuture\u003cModel\u003e getModel(Ctx ctx) {\n\n}\n```\n\nThis would generate graphql_api.schema.dart\n\n```dart\n\n```\n\n\n### Interfaces\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Interfaces)\n\n- inheritFrom\n\nThe `inheritFrom` function in `GraphQLObjectType` receives an Interface and assigns it's argument as  \na super type, now the Object will implement the Interface passed as parameter.\n\n## Inputs and Input Objects\n\nInput types specify the structure of the values that inputs to resolvers should have. Scalars and Enums can be passed as input to resolvers. Wrapper types such as List and NonNull types of Scalars and Enums, also can be passed, however for more complex Objects with nested fields you will need to use `GraphQLInputObjectType`. Similar `GraphQLObjectType`, a `GraphQLInputObjectType` can have fields.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Input-Objects)\n\n// TODO: 1A customDeserialize with SerdeCtx deserializers\n\n```dart\nfinal inputModel = GraphQLInputObjectType(\n  'ModelInput',\n  description: '',\n  inputs: [\n\n  ],\n);\n```\n\nField inputs (or Arguments) can be used in multiple places:\n\n- `GraphQLObjectType.fields.inputs`: Inputs in field resolvers\n\n- `GraphQLInputObjectType.fields`: Fields in Input Objects\n\n- `GraphQLDirective.inputs`: Inputs in directives\n\nNot all types can be input types, in particular, object types and union types can't be input types nor part of a `GraphQLInputObjectType`.\n\n```dart\nstatic bool isInputType(GraphQLType type) {\n  return type.when(\n    enum_: (type) =\u003e true,\n    scalar: (type) =\u003e true,\n    input: (type) =\u003e true,\n    object: (type) =\u003e false,\n    union: (type) =\u003e false,\n    list: (type) =\u003e isInputType(type.ofType),\n    nonNullable: (type) =\u003e isInputType(type.ofType),\n  );\n}\n```\n\n### Example \u003c!-- omit in toc --\u003e\n\n```graphql\ninput ComplexInput {\n  value: String!\n}\n\n# The fields:\n(\n  \"\"\"The amount\"\"\"\n  @deprecated\n  amount: Int = 2\n  names: [String!]\n  complex: ComplexInput!\n)\n```\n\n```dart\n@GraphQLInput()\nclass ComplexInput {\n  const ComplexInput({required this.value});\n  /// The value\n  final String value;\n\n  factory ComplexInput.fromJson(Map\u003cString, Object?\u003e json) =\u003e\n    ComplexInput(\n      value: json['value']! as String,\n    );\n}\n\nfinal fields = [\n  GraphQLFieldInput(\n    'amount',\n    graphQLInt,\n    defaultValue: 2,\n    description: 'The amount',\n    // an empty String will use the default deprecation reason\n    deprecationReason: '',\n  ),\n  GraphQLFieldInput(\n    'names',\n    listOf(graphQLString.nonNull()),\n  ),\n  GraphQLFieldInput(\n    'complex',\n    complexInputGraphQLInputType.nonNull(),\n  ),\n];\n\n// can be used in:\n// - `GraphQLObjectType.fields.inputs`\n// - `GraphQLInputObjectType.fields`\n// - 'GraphQLDirective.inputs'\n\nfinal object = GraphQLObjectType(\n  'ObjectName',\n  fields: [\n    stringGraphQLType.field(\n      'someField',\n      inputs: fields,\n      resolve: (_, Ctx ctx) {\n        final Map\u003cString, Object?\u003e args = ctx.args;\n        assert(args.containKey('complex'));\n        assert(args['names'] is List\u003cString\u003e?);\n        assert(args['amount'] is int?);\n        return '';\n      }\n    )\n  ]\n);\n\nfinal objectInput = GraphQLInputObjectType(\n  'InputObjectName',\n  fields: fields,\n  // ...\n);\n\nfinal directive = GraphQLDirective(\n  name: 'DirectiveName',\n  inputs: fields,\n  // ...\n);\n```\n\n### InputObject.isOneOf\n\n[Discussion](https://github.com/graphql/graphql-spec/pull/825)\n\noneOf input object types allow you to specify that an object should contain only one of the provided fields. The fields should be nullable and should not have a default value. This is similar to [union](#unions) types. However, oneOf input types can be used as inputs and their variants (or fields) can be any input type such as a custom scalar, they are not constrained to object types.\n\n```graphql\ninput EmailPassword {\n  email: String!\n  password: String!\n}\n\ninput LogInOption @oneOf {\n  email: EmailPassword\n  token: String\n}\n\ntype Mutation {\n  login(option: LogInOption!): Boolean!\n}\n\nmutation loginMut {\n  login(option: { email: { email: \"email@example.com\" password: \"pass\" } })\n}\n```\n\n### InputObject.fromJson\n\nFor code generation, each class annotated as `GraphQLInput` should have a factory constructor or static method name `fromJson` in its class definition. This will be used as the method for deserializing instances of this class.\n\n## Unions\n\nSimilar to enums, Unions are restricted to a set of predefined variants, however the possible types are always the more complex `GraphQLObjectType`.\n\nPer the GraphQL spec, Unions can't be (or be part of) Input types and their possible types is a non empty collection of unique `GraphQLObjectType`.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Unions)\n\nTo have the following GraphQL type definitions:\n\n```graphql\nunion ModelEvent = ModelAdded | ModelRemoved\n\ntype ModelRemoved {\n  \"The removed model id\"\n  modelId: ID!\n}\n\ntype ModelAdded {\n  model: Model!\n}\n\ntype Model {\n  id: ID!\n}\n```\n\nYou could provide this definitions:\n\n```dart\nimport 'package:leto_schema/leto_schema.dart';\n\nfinal model = objectType(\n  'Model',\n  fields: [\n      graphQLIdType.nonNull().field('id'),\n  ],\n);\nfinal modelAddedGraphQLType = objectType(\n  'ModelAdded',\n  fields: [model.nonNull().field('model')],\n);\nfinal modelRemovedGraphQLType = objectType(\n  'ModelRemoved',\n  fields: [graphQLIdType.nonNull().field('modelId')],\n);\n\nfinal union = GraphQLUnionType(\n  // name\n  'ModelEvent',\n  // possibleTypes\n  [\n      modelAddedGraphQLType,\n      modelRemovedGraphQLType,\n  ],\n);\n```\n\n- `extractInner`\n\nWhen the members of the union type are not\n\n### Freezed Unions\n\nWith code generation, Unions with [freezed](https://github.com/rrousselGit/freezed) also work without trouble.\n\n```dart\nimport 'package:leto_schema/leto_schema.dart';\nimport 'package:freezed_annotation/freezed_annotation.dart';\n\n@GraphQLObject()\nclass Model {\n  final String id;\n\n  const Model(this.id);\n}\n\n@GraphQLObject()\n@freezed\nclass ModelEvent with _$ModelEvent {\n  const factory ModelEvent.added(Model model) = ModelAdded;\n  const factory ModelEvent.removed(\n    @GraphQLDocumentation(type: 'graphQLIdType', description: 'The removed model id')\n    String modelId,\n    // you can also provide a private class\n  ) = _ModelRemoved;\n}\n```\n\n\u003c!-- include{unions-example-generator} --\u003e\n```dart\nGraphQLAttachments unionNoFreezedAttachments() =\u003e const [ElementComplexity(50)];\n\n@AttachFn(unionNoFreezedAttachments)\n@GraphQLDocumentation(\n  description: '''\nDescription from annotation.\n\nUnion generated from raw Dart classes''',\n)\n@GraphQLUnion(name: 'UnionNoFreezedRenamed')\nclass UnionNoFreezed {\n  const factory UnionNoFreezed.a(String value) = UnionNoFreezedA.named;\n  const factory UnionNoFreezed.b(int value) = UnionNoFreezedB;\n}\n\n@GraphQLObject()\nclass UnionNoFreezedA implements UnionNoFreezed {\n  final String value;\n\n  const UnionNoFreezedA.named(this.value);\n}\n\n@GraphQLObject()\nclass UnionNoFreezedB implements UnionNoFreezed {\n  final int value;\n\n  const UnionNoFreezedB(this.value);\n}\n\n@Query()\nList\u003cUnionNoFreezed\u003e getUnionNoFrezzed() {\n  return const [UnionNoFreezed.a('value'), UnionNoFreezed.b(12)];\n}\n```\n\u003c!-- include-end{unions-example-generator} --\u003e\n\n## Wrapping Types\n\nWrapping types allow to modify the behavior of the inner (wrapped) type. The inner types can be of any `GraphQLType` and wrapping types can be Output or Input Types if the wrapped type is an Output or Input type. GraphQL has two wrapping types, `GraphQLNonNullType` and `GraphQLListType`.\n\n## Non-Nullable\n\n`GraphQLNonNullType` allows you to represent a non-nullable or required value. By default, all GraphQL Types are nullable or optional, if you want to represent a required input or specify that a given output is always present (non-null), you want to use the `GraphQLNonNullType` wrapping type.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Non-Null)\n\n\nIn GraphQL this is represented using the `!` exclamation mark after a given type expression. In Dart you can use the `nonNull()` method present in each `GraphQLType`, which will return a non-nullable `GraphQLNonNullType` with it's inner type, the type from which `nonNull` was called. For example, `graphQLString.nonNull()` will be a `String!` in GraphQL.\n\n## Lists\n\n`GraphQLListType` allows you to represent a collection of values.\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-List)\n\nThis values can be of any `GraphQLType` and List types can be Output or Input Types if the Wrapped type is an Output or Input type. For example, a List of Union types is an Output type while a List of Strings (scalar types) can be an Output or Input type. You can use the `\u003ctype\u003e.list()` method present in each `GraphQLType` or the `listOf(\u003ctype\u003e)` global utility function to create a `GraphQLListType`. For example, `graphQLString.list()` will be a `[String]` in GraphQL.\n\n### Example \u003c!-- omit in toc --\u003e\n\nIn GraphQL, you can represent it like this:\n\n```graphql\ntype Model {\n  listField(listInput: [String]!): [InterfaceModel!]\n}\n\ninterface InterfaceModel {\n  name: String\n}\n```\n\nUsing Dart:\n\n```dart\nimport 'package:leto_schema/leto_schema.dart';\n\nabstract class InterfaceModel {\n  String get name;\n}\n\nclass Model {\n  List\u003cInterfaceModel\u003e? list(List\u003cString?\u003e listInput) {\n    throw Unimplemented();\n  }\n}\n\nfinal interfaceModel = objectType\u003cInterfaceModel\u003e(\n  'InterfaceModel',\n  fields: [\n    graphQLString.field(\n      'name',\n      resolve: (InterfaceModel obj, Ctx ctx) =\u003e obj.name,\n    )\n  ],\n  isInterface: true,\n);\n\nfinal model = objectType\u003cModel\u003e(\n  'Model',\n  fields: [\n    interfaceModel.nonNull().list().field(\n      'listField',\n      inputs: [\n        listOf(graphQLString).nonNull().inputField('listInput'),\n      ],\n      resolve: (Model obj, Ctx ctx) =\u003e \n        obj.listField(ctx.args['listInput'] as List\u003cString?\u003e) \n    )\n  ]\n);\n\n```\n\nWith code generation, you just annotate the different classes with `@GraphQLObject()` (or the expected annotation) and the fields and models containing Dart Lists or non-nullable types will be generated using `GraphQLListType` or `GraphQLNonNullType` as required.\n\n```dart\nimport 'package:leto_schema/leto_schema.dart';\n\n@GraphQLObject()\nabstract class InterfaceModel {\n  String get name;\n}\n\n@GraphQLObject()\nclass Model {\n  List\u003cInterfaceModel\u003e? list(List\u003cString?\u003e listInput) {\n    throw Unimplemented();\n  }\n}\n```\n\n## Abstract Types\n\nAbstract types like Interfaces and Unions, require type resolution of its variants on execution. For that, we provide a couple of tools explained in the following sections. You can read the code that executes the following logic in package:leto's `GraphQL.resolveAbstractType` method.\n\n### resolveType\n\nA parameter of Interface and Union types is a function with the signature: `String Function(Object result, T abstractType, ResolveObjectCtx ctx)`. Given a resolved result, the abstract type itself and the ObjectCtx, return the name of the type associated with the result value.\n\n### Generics\n\nWe compare the resolved result's Dart type with the possible types generic type parameter, if there is only one match (withing the possible types), that will be the resolved type. This happens very often, specially with code generation or when providing a distinct class for each `GraphQLObjectType`.\n\nThis can't be used with Union types which are wrappers over the inner types (like `Result\u003cV, E\u003e` or `Either\u003cL, R\u003e`), since generic type of the possible types (`V` and `E`) will not match the wrapper type (`Result`). For this cases you will need to provide a `resolveType` and `extractInner` callbacks. With freezed-like unions you don't have to do that since the variants extend the union type.\n\n### isTypeOf\n\nIf any of the previous fail, you can provide a `isTypeOf` callback for objects, which determine whether a given value is an instance of that `GraphQLObjectType`.\n\n### \\_\\_typename\n\nIf the resolved result is a `Map` and contains a key \"\\_\\_typename\", we will use it to resolve the type by comparing it with possible types names. If there is a match, we use the matched type in the next steps of execution.\n\n### Serialize and validate\n\n## Advanced Types\n\n### Provided Types\n\n\n- PageInfo: Following the [relay connections spec](https://relay.dev/graphql/connections.htm).\n\n\n### Cyclic Types\n\nTypes which use themselves in their definition have to reuse previously created instances. The type's field lists are mutable, which allow you to instantiate the type and then modify the fields of the type. For example, an User with friends:\n\n```dart\nclass User {\n  const User(this.friends);\n  final List\u003cUser\u003e friends;\n}\nGraphQLObjectType\u003cUser\u003e? _type;\nGraphQLObjectType\u003cUser\u003e get userGraphQLType {\n  if (_type != null) return _type; // return a previous instance\n  final type = objectType\u003cUser\u003e(\n    'User',\n    // leave fields empty (or don't pass them)\n    fields: [],\n  );\n  _type = type; // set the cached value\n  type.fields.addAll([ // add the fields\n    listOf(userGraphQLType.nonNull()).nonNull().field(\n      'friends',\n      resolve: (obj, _) =\u003e obj.friends,\n    ),\n  ]);\n  return type;\n}\n```\n\nCode generation already does it, so you don't have to worry about it when using it.\n\n### Custom Scalars\n\nYou can extend the `GraphQLScalarType` or create an instance directly with `GraphQLScalarTypeValue`. For example, to support the `Decimal` type from https://github.com/a14n/dart-decimal you can use the following code:\n\n\u003c!-- include{custom-scalar-decimal} --\u003e\n```dart\nimport 'package:decimal/decimal.dart';\nimport 'package:leto_schema/leto_schema.dart';\n\nexport 'package:decimal/decimal.dart';\n\nfinal decimalGraphQLType = GraphQLScalarTypeValue\u003cDecimal, String\u003e(\n  name: 'Decimal',\n  deserialize: (_, serialized) =\u003e decimalFromJson(serialized)!,\n  serialize: (value) =\u003e decimalToJson(value)!,\n  validate: (key, input) =\u003e (input is num || input is String) \u0026\u0026\n          Decimal.tryParse(input.toString()) != null\n      ? ValidationResult.ok(input.toString())\n      : ValidationResult.failure(\n          ['Expected $key to be a number or a numeric String.'],\n        ),\n  description: 'A number that allows computation without losing precision.',\n  specifiedByURL: null,\n);\n\nDecimal? decimalFromJson(Object? value) =\u003e\n    value == null ? null : Decimal.parse(value as String);\n\nString? decimalToJson(Decimal? value) =\u003e value?.toString();\n```\n\u003c!-- include-end{custom-scalar-decimal} --\u003e\n\nFor code generation you need to provide `customTypes` in the [build.yaml](https://github.com/dart-lang/build/blob/master/docs/faq.md) file of you project:\n\n```yaml\ntarget:\n  default:\n    builders:\n      leto_generator:graphql_types:\n        options:\n          customTypes:\n            - name: \"Decimal\"\n            import: \"package:\u003cyour_package_name\u003e/\u003cpath_to_implementation\u003e.dart\"\n            getter: \"decimalGraphQLType\"\n      leto_generator:graphql_resolvers:\n        options:\n          customTypes:\n            - name: \"Decimal\"\n              import: \"package:\u003cyour_package_name\u003e/\u003cpath_to_implementation\u003e.dart\"\n              getter: \"decimalGraphQLType\"\n```\n\n### Generic Types\n\nWork in progress\n\n```dart\n\nclass ErrC\u003cT\u003e {\n  final String? message;\n  final T value;\n\n  const ErrC(this.value, [this.message]);\n}\n\nGraphQLObjectType\u003cErrC\u003cT?\u003e\u003e errCGraphQlType\u003cT extends Object\u003e(\n  GraphQLType\u003cT, Object\u003e tGraphQlType, {\n      String? name,\n  }\n) {\n  return objectType(\n      name ?? 'ErrC${tGraphQlType is GraphQLTypeWrapper ? (tGraphQlType as GraphQLTypeWrapper).ofType : tGraphQlType}',\n      isInterface: false,\n      interfaces: [],\n      description: null,\n    fields: [\n      field('message', graphQLString,\n          resolve: (obj, ctx) =\u003e obj.message,),\n      field('value', tGraphQlType,\n          resolve: (obj, ctx) =\u003e obj.value,)\n    ],\n  );\n}\n\n\n```\n\n- With code generation\n\n```dart\nimport 'package:leto/leto.dart';\npart 'errc.g.dart';\n\n@GraphQLObject()\nclass ErrC\u003cT\u003e {\n  final String? message;\n  final T value;\n\n  const ErrC(this.value, [this.message]);\n}\n```\n\nWhich generates in 'errc.g.dart':\n\n```dart\n\nMap\u003cString, GraphQLObjectType\u003cErrC\u003e\u003e _errCGraphQlType = {};\n\n/// Auto-generated from [ErrC].\nGraphQLObjectType\u003cErrC\u003cT\u003e\u003e errCGraphQlType\u003cT extends Object\u003e(\n  GraphQLType\u003cT, Object\u003e tGraphQlType,\n) {\n  final __name =\n      'ErrC${tGraphQlType is GraphQLTypeWrapper ? (tGraphQlType as GraphQLTypeWrapper).ofType : tGraphQlType}';\n  if (_errCGraphQlType[__name] != null)\n    return _errCGraphQlType[__name]! as GraphQLObjectType\u003cErrC\u003cT\u003e\u003e;\n\n  final __errCGraphQlType = objectType\u003cErrC\u003cT\u003e\u003e(\n      'ErrC${tGraphQlType is GraphQLTypeWrapper ? (tGraphQlType as GraphQLTypeWrapper).ofType : tGraphQlType}',\n      isInterface: false,\n      interfaces: [],\n      description: null);\n  _errCGraphQlType[__name] = __errCGraphQlType;\n  __errCGraphQlType.fields.addAll(\n    [\n      field('message', graphQLString,\n          resolve: (obj, ctx) =\u003e obj.message,\n          inputs: [],\n          description: null,\n          deprecationReason: null),\n      field('value', tGraphQlType.nonNull(),\n          resolve: (obj, ctx) =\u003e obj.value,\n          inputs: [],\n          description: null,\n          deprecationReason: null)\n    ],\n  );\n\n  return __errCGraphQlType;\n}\n\n```\n\n# Resolvers\n\nGraphQL resolvers execute the logic for each field and return the expected value typed according to the schema. In Dart this are functions that receive the parent's object value and the field's [`Ctx`](#ctx), and return the execution result. Simple fields may only return a property of the parent object value. However, there may also be complex resolvers, such as mutations, that validate the input data and create rows in a database, or queries that retrieve multiple rows according to complex authorization logic.\n\n## Queries and Mutations\n\nEach field (`GraphQLObjectField`) in an object type (`GraphQLObjectType`) contains a `resolve` parameter, this will be used to resolve all fields. The first argument to `resolve` with be the parent object, if this field is in the root Query or Mutation Object, the value will be the the root value passed as an argument to `GraphQL.parseAndExecute` and a `SubscriptionEvent` if this is a subscription field (more in the [subscription](#subscriptions) section). The second argument will be the field's [`Ctx`](#ctx), with it you can access defined Refs with `Ref.get(ctx)` and view more information about the resolved field or GraphQL request. When using `package:leto_shelf`, you can access the HTTP request and modify the HTTP response, more information in the [package's README](https://github.com/juancastillo0/leto/tree/main/leto_shelf).\n\n\n```graphql\ntype Query {\n  someField: String\n}\n\ntype CustomMutation {\n  updateSomething(arg1: Float): Date\n}\n\n\"\"\"An ISO-8601 Date.\"\"\"\nscalar Date\n\ntype schema {\n  query: Query\n  mutation: CustomMutation\n}\n\n```\n\nIn Dart:\n\n```dart\nfinal query = objectType(\n  'Query',\n  fields: [\n    graphQLString.field(\n      'someField',\n      resolve: (Object? rootObject, Ctx ctx) =\u003e 'someFieldOutput',\n    ),\n  ],\n);\n\nfinal customMutation = objectType(\n  'CustomMutation',\n  fields: [\n    graphQLDate.field(\n      'updateSomething',\n      inputs: [\n        graphQLFloat.inputField('arg1')\n      ],\n      resolve: (Object? rootObject, Ctx ctx) {\n        final arg1 = ctx.args['arg1'] as double?;\n        return DateTime.now();\n      },\n    ),\n  ],\n);\n\nfinal schema = GraphQLSchema(\n  queryType: query,\n  mutation: customMutation,\n);\n\n```\n\n\nWhen using `package:leto_shelf`, POST requests can be used for Queries or Mutations. However, GET requests can only be used for Queries, if a Mutation operation is sent using a GET request, the server will return a 405 status code (MethodNotAllowed) following the [GraphQL over HTTP specification](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md).\n\n\n## Subscriptions\n\nEach field (`GraphQLObjectField`) in an object type (`GraphQLObjectType`) contains a `subscribe` parameter that receives the root value and a `Ctx`, and returns a Stream of values of the field's type `Stream\u003cT\u003e Function(Ctx\u003cP\u003e ctx, P parent)`. The Stream of values will be returned in the `data` field of the `GraphQLResult` returned on execution.\n\nIf using a WebSocket server, the client should support either `graphql-transport-ws` or `graphql-ws` sub-protocols.\n\n```dart\n\nfinal apiSchema = GraphQLSchema(\n  queryType: objectType('Query'),\n  subscriptionType: objectType(\n    'Subscription',\n    fields: [\n      graphQLInt.nonNull().fields(\n        'secondsSinceSubscription',\n        subscribe: (Ctx ctx, Object rootValue) {\n          return Stream.periodic(const Duration(seconds: 1), (secs) {\n            return secs;\n          });\n        }\n      ),\n    ]\n  ),\n);\n\nFuture\u003cvoid\u003e main() async {\n  final GraphQLResult result = await GraphQL(apiSchema).parseAndExecute(\n    'subscription { secondsSinceSubscription }',\n  );\n\n  assert(result.isSubscription);\n  final Stream\u003cGraphQLResult\u003e stream = result.subscriptionStream!;\n  stream.listen((event) {\n    final data = event.data as Map\u003cString, Object?\u003e;\n    assert(data['secondsSinceSubscription'] is int);\n\n    print(data['secondsSinceSubscription']);\n  });\n}\n\n```\n\nThe `resolve` callback in a subscription field will always receive a `SubscriptionEvent` as it's parent.\nFrom that you can access the event value with `SubscriptionEvent.value` which will be the emitted by the Stream returned in the `subscribe` callback. The error handling in each callback is different, if an error is thrown in the `subscribe` callback, the Stream will end with an error. But if you throw an error in the `resolve` callback it will continue sending events, just the event resolved with a thrown Object will have `GraphQLError`s as a result of processing the thrown Object (More information in [Error Handling](#error-handling)).\n\nFor usage in a web server you can use any of the [web server integrations](#web-integrations) which support WebSocket subscriptions (For example, [leto_shelf](https://github.com/juancastillo0/leto/tree/main/leto_shelf)).\n\n### Examples\n\nFor a complete subscriptions example with events from a database please see the [chat_example](https://github.com/juancastillo0/leto/tree/main/chat_example), in particular the [events](https://github.com/juancastillo0/leto/tree/main/chat_example/server/lib/events) directory.\n\n\n## Request Contexts\n\nAll `Ctx`s implement `ScopedHolder`, so that then can be used to retrieve values from the scoped map, more in [`ScopedMap`](#scopedmap).\n### Ctx\n\n[Source Code](https://github.com/juancastillo0/leto/blob/main/leto_schema/lib/src/req_ctx.dart)\n\nA unique context for each field resolver\n\n- args: the arguments passed as inputs to this field\n- object: the parent Object's value, same as the first parameter of `resolve`.\n- objectCtx: the parent Object's execution context ([ObjectExecutionCtx](#objectexecutionctx))\n- field: The `GraphQLObjectField` being resolved\n- path: The path to this field\n- executionCtx: The request's execution context ([ExecutionCtx](#executionctx))\n- lookahead: A function for retrieving nested selected fields. More in the [LookAhead section](#lookahead-eager-loading)\n\n### ObjectExecutionCtx\n\nThis is the context associated with an object execution, can be retrieved through `Ctx.objectCtx`. There will be as many instances as there are objects to execute in the request. Contains the value of the object, the field selections and the path in the GraphQL request to this object.\n\n### ExecutionCtx\n\nThis is the context associated with the execution phase of the request, created after the validation phase.\nContains validated and coerced (parsed) input values and the specific validated operation within the request's document to execute. It has an `errors` list with the encountered errors during execution. Can be retrieved with `ObjectExecutionCtx.executionCtx`.\n\n### RequestCtx\n\nThis is the base context associated with the request, contains the raw information about the GraphQL document, the raw (not validated nor parsed) input values, input extensions, the schema, root value and the scoped map for this request. Can be retrieved with `ExecutionCtx.requestCtx`.\n\n# Validation\n\n## Schema Validation\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Type-System)\n\nImplements the \"Type Validation\" sub-sections of the specification's \"Type System\" section.\n\nGuaranties that the `GraphQLSchema` instance is valid, verifies the Type System validations in the specification. For example, an Object field's type can only be an Output Type or an Union should have at least one possible type and all of them have to be Object types.\n\nThis will be executed before stating a GraphQL server. Leto implements all of the Specification's schema validation. The code for all rules can be found in the [validate_schema.dart](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/validate/validate_schema.dart) file in `package:leto_schema`.\n\n## Document Validation\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Validation)\n\nThis will be executed before executing any request. Leto implements all of the Specification's document validation. The code for all rules can be found in the [validate](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/validate) folder in `package:leto_schema`.\n\nYou can add custom validation rules to a server with the `GraphQL.customValidationRules` parameter, they will be added on top of the `specifiedValidationRules`. One example of a custom validation rule is the [Query Complexity](#query-complexity) validation.\n\n\n## Query Complexity\n\n[Tests](https://github.com/juancastillo0/leto/tree/main/leto_schema/test/validation/query_complexity_test.dart)\n\nThis document validation rule allows you to restrict the complexity of a GraphQL request.\n\n\nThe provided `queryComplexityRuleBuilder` returns a `ValidationRule` that reports errors when the `maxComplexity` or `maxDepth` configuration parameters are reached.\n\n- `maxComplexity`\n\nSpecifies the maximum complexity for a given operation. The complexity is measured based on the selected fields and should be. If this complexity is surpassed (is greater) a validation error will be reported.\n\n- `maxDepth`\n\nSpecifies the maximum depth for a given operation. The depth is defined as the number of objects (including the root operation object) that have to be traversed to arrive to a given field. If this depth is surpassed (is greater) a validation error will be reported.\n\n\nThe complexity for each fieldNode is given by:\n\n`complexity = fieldComplexity + (childrenComplexity + fieldTypeComplexity) * complexityMultiplier`\n\nWhere fieldComplexity is the `ElementComplexity` in\n`GraphQLObjectField.attachments` or `defaultFieldComplexity`\nif there aren't any.\n\nchildrenComplexity is:\n- scalar or enum (leaf types): 0\n- object or interface: sum(objectFieldsComplexities)\n- union: max(possibleTypesComplexities)\n\nfieldTypeComplexity will be taken as the `ElementComplexity`\nfrom `GraphQLNamedType.attachments` or 0 if there aren't any.\n\nIf the fieldType is a `GraphQLListType`, complexityMultiplier\nwill be the provided `listComplexityMultiplier`, otherwise 1.\n\n## Skip validation with Persisted Queries\n\nTODO: 1A\n\nUsing the `PersistedQueriesExtensions` you can set the `skipValidation` parameter so that the validation is skipped for already cached (and validated) documents.\n\n## Input Validation\n\nInput validation refers to the verification of the values or structure of the payload sent as input in a request. It could, of coursed, be performed manually before the execution of each request. However, we provide a couple of tools to help with the process, in particular using code generation and the [`valida` package](https://github.com/juancastillo0/valida).\n\nThe following example shows an input object `ConnectionArguments` with the annotations `@Valida()` and its fields `first` and `last` with the annotation `@ValidaNum(min: 1)`. If the `ConnectionArguments` object is used as input in a resolver, the validation is performed over the input value on execution and an error will be thrown if either `first` or `last` are less than 1. For more information on the supported annotations and validations, view the [`valida` package](https://github.com/juancastillo0/valida).\n\n\u003c!-- include{code-generation-valida} --\u003e\n```dart\n@JsonSerializable()\n@Valida()\n@GraphQLInput()\nclass ConnectionArguments {\n  /// Returns the items in the list that come before the specified cursor.\n  final String? before;\n\n  /// Returns the items in the list that come after the specified cursor.\n  final String? after;\n\n  /// Returns the first n items from the list.\n  @ValidaNum(min: 1)\n  final int? first;\n\n  /// Returns the last n items from the list.\n  @ValidaNum(min: 1)\n  final int? last;\n\n  const ConnectionArguments({\n    this.before,\n    this.after,\n    this.first,\n    this.last,\n  });\n\n  factory ConnectionArguments.fromJson(Map\u003cString, Object?\u003e json) =\u003e\n      _$ConnectionArgumentsFromJson(json);\n\n  Map\u003cString, Object?\u003e toJson() =\u003e _$ConnectionArgumentsToJson(this);\n}\n```\n\u003c!-- include-end{code-generation-valida} --\u003e\n\n# Miscellaneous\n\n## `GraphQLResult`\n\n[GraphQL Specification](https://spec.graphql.org/draft/#sec-Response)\n\nThe returned `GraphQLResult` is the output of the execution of a GraphQL request it contains the encountered `GraphQLError`s, the output `extensions` and the `data` payload. The `GraphQLResult.toJson` Map is used by `package:leto_shelf` when constructing an HTTP response's body.\n\n- The `data` is a `Map\u003cString, Object?\u003e?` for Queries and Mutations or a `Stream\u003cGraphQLResult\u003e` for subscriptions. It has the payload returned by the resolvers during execution. Will be null if there was an error in validation or in the execution of a non-nullable root field. If there was an error in validation, the `data` property will not be set in the `GraphQLResult.toJson` Map following the [spec](https://spec.graphql.org/draft/#sec-Response).\n  \n- The `errors` contain the `GraphQLError`s encountered during validation or execution. If a resolver throws an error, it will appear in this error list. If the field's return type is nullable, a null value will be set as the output for that field. If the type is non-nullable the resolver will continue to throw an exception until a nullable field is reached or the root resolver is reached (in this case the `GraphQLResult.data` property will be null).\n\n- The `extensions` is a  `Map\u003cString, Object?\u003e?` with custom values that you may want to provide to the client. All values should be serializable since they may be returned as part of an HTTP response. Most `GraphQLExtensions` modify this values to provide additional functionalities. The keys for the `extensions` Map should be unique, you may want to prefix them with an identifier such as a package name.\n\n## `ScopedMap`\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto_schema/lib/src/req_ctx.dart)\n\nAn `ScopedMap` allows you to pass and use dependencies or services within your resolvers or extensions. It consists of multiple maps, one for each scope, and a set of immutable references (or keys) with overridable defaults. \n\nTo retrieve a value from a reference, the map checks whether a value was already instantiated for the scope or in any of its parents. If it has not been instantiated, the default is returned and saved in the scope.\n\nThis forms a tree of scopes, where one node scope has access to its parent values.\n\nTo override the value of a reference for a given scope you instantiate a `ScopedMap` with the values to override, if it is a child, you can pass the parent as a parameter to the constructor.\n\n### `ScopedHolder`\n\nA `ScopedHolder` is simply an object that contains a `ScopedMap get globals;` getter. This map represents the scope associated with the object. As discussed in the [Request Contexts section](#request-contexts), all contexts are (implement) `ScopedHolder`s and therefore have access to the values in the scope.\n\n### `ScopedRef`\n\nYou can specify the behavior and the default values of references using `ScopedRef`. As explained in the source code docs, a \"global\" ref will instantiate a value accessible to all scopes in a scope tree. A \"local\" ref will instantiate the value (and make it accessible) only to children scopes in which the value is instantiated.\n\n### Example usage\n\nExample usage with the `GraphQL` executor and different ways to override the values is shown in the following code snippet:\n\n```dart\nfinal ScopedRef\u003cint\u003e ref = ScopedRef.global((ScopedMap scope) =\u003e 4);\nfinal schema = GraphQLSchema(\n  queryObject: objectType(\n    'Query', \n    fields: [\n      graphQLint.field('fieldName', (ctx) =\u003e ref.get(ctx)),\n    ],\n  ),\n);\n\nfinal executorWithDefault = GraphQL(schema);\n\nvar result = await executorWithDefault.parseAndExecute('{fieldName}');\nvar data = result.data as Map\u003cString, Object?\u003e;\nassert(data['fieldName'] == 4);\n\nresult = await executorWithDefault.parseAndExecute(\n  '{fieldName}', \n  globalVariables: {\n    ref: 6,\n  },\n);\ndata = result.data as Map\u003cString, Object?\u003e;\nassert(data['fieldName'] == 6);\n\nfinal executorWithOverride = GraphQL(\n  schema,\n  globalVariables: ScopedMap(\n    {\n      ref: 5,\n    },\n  ),\n);\n\nresult = await executorWithOverride.parseAndExecute('{fieldName}');\ndata = result.data as Map\u003cString, Object?\u003e;\nassert(data['fieldName'] == 5);\n```\n\n## Error Handling\n\nOne typically has multiple options to represent and let the client know that there was an error in the request.\n\nIf using HTTP (or WebSockets) fatal errors such as a malformed query string are already handled and follow the spec in each case.\n\n### Exceptions and `GraphQLError`\n\nIf an error does not require a different type to be expressed and a more implicit approach is preferable, perhaps for errors that happen in most endpoints (authentication, authorization, input validation), one can use exceptions and send the necessary information through custom extensions in the payload.\n\n```dart\n@Query()\nFuture\u003cint\u003e userChats(Ctx ctx) async {\n  final user = await userFromCtx(ctx);\n  if (user == null) {\n    throw GraphQLError(\n      'This endpoint requires an authenticated user.', // message\n      extensions: {\n        'appError': {\n          'code': 'UNAUTHENTICATED',\n        },\n      },\n      // You can also pass a `sourceError` and `stackTrace` if the given error\n      // was generated from an exception\n      // sourceError, \n      // stackTrace,\n    );\n  } \n  // You could also throw a list of errors with GraphQLException\n  final errors = [\n    if (!user.emailVerified)\n      GraphQLError(\n        'This functionality requires that you verify your email.', // message\n        extensions: {\n          'appError': {\n            'code': 'UNVERIFIED_EMAIL',\n          },\n        },\n      ),\n    if (!user.canReadUserChats)\n      GraphQLError(\n        'You do not have access to this functionality.', // message\n        extensions: {\n          'appError': {\n            'code': 'UNAUTHORIZED',\n          },\n        },\n      ),\n    ];\n  if (errors.isNotEmpty) throw GraphQLException(errors);\n  // AUTHORIZED, now get the userChats\n}\n```\n\nOf course, this could be abstracted and structured in a better way. For example, the \"UNAUTHENTICATED\" error could be a constant or it could be thrown inside `userFromCtx(ctx)` call. The `appError` key could be anything you want, but is has to be unique to avoid overriding other extensions.\n\n\n### Result types\n\n- Result\n\n```graphql\n\"\"\"\nSomethingT! when the operation was successful or SomethingE! when an error was encountered.\n\"\"\"\ntype ResultSomethingTSomethingE {\n  ok: SomethingT\n  err: SomethingE\n  isOk: Boolean!\n}\n```\n\n- ResultU\n\n```graphql\n\"\"\"\nSomethingT when the operation was successful or SomethingE when an error was encountered.\n\"\"\"\nunion ResultUSomethingTSomethingE = SomethingT | SomethingE\n```\n\n### Error lists and interfaces\n\nThe error in the result union or object could be a simple object specific to the resolver. However, it could also by an union, an object that implements an \"ApplicationError\" interface or a list of errors, where the errors could also be of union type or objects that implement interfaces, or both. For a more thorough discussion on the topic, this [guide to GraphQL errors](https://productionreadygraphql.com/2020-08-01-guide-to-graphql-errors) may help you.\n\n## Hot Reload and Cycles\n\nSince type and field schema definitions should probably be reused, this may pose a conflict to the beautifully hot reload capabilities of Dart. The cached instances will not change unless you execute the more expensive hot restart, which may also cause you to lose other state when developing.\n\nBecause of this, we provide an utility class `HotReloadableDefinition` that handles definition caching, helps with cycles in instantiation and controls the re-instantiation of values. It receives a `create` function that should return a new instance of the value. This value will be cached and reused throughout the schema's construction. To retrieve the current instance you can use the `HotReloadableDefinition.value` getter. \n\nThe provided `create` function receives a `setValue` callback that should be called right after the instance's creation (with the newly constructed instance as argument), this is only necessary if the instance definition may contain cycles.\n\nTo re-instantiate all values that use `HotReloadableDefinition` you can execute the static `HotReloadableDefinition.incrementCounter` which will invalidate previously created instances, if you call `HotReloadableDefinition.value` again, a new instance will be created with the, potentially new, hot reloaded code.\n\nWhen using code generation all schema definitions use the `HotReloadableDefinition` class to create type and field instances, you only need to call the generated `recreateGraphQLApiSchema` function to instantiate the `GraphQLSchema` each time the application hot reloads.\n\nYou can use other packages to hot reload the dart virtual machine (vm), for example:\n\n- If using shelf you may want to try https://pub.dev/packages/shelf_hotreload. Most shelf examples in this repository already use this package.\n  \n- You could also search in https://pub.dev or try https://pub.dev/packages/hotreloader, which is used by `package:shelf_hotreload`.\n\n\n# Solving the N+1 problem\n\nWhen fetching nested fields, a specific resolvers could be executed multiple times for each request since the parent object will execute it for all its children. This may pose a problem when the resolver has to do non-trivial work for each execution. For example, retrieving a row from a database. To solve this problem, Leto provides you with two tools: LookAhead and DataLoader.\n\n## LookAhead (Eager loading)\n\nYou can mitigate the N+1 problem by fetching all the necessary information from the parent's resolver so that when the nested fields are executed they just return the previously fetch items. This would prevent all SQL queries for nested fields since the parent resolver has all the information about the selected nested fields and can use this to execute a request that fetches the necessary columns or joins.\n\n```dart\n@GraphQLObject()\nclass Model {\n    final String id;\n    final String name;\n    final NestedModel? nested;\n\n    const Model(this.id, this.name, this.nested);\n}\n\n@GraphQLObject()\nclass NestedModel {\n    final String id;\n    final String name;\n\n    const NestedModel(this.id, this.name);\n}\n\nfinal modelRepo = ScopedRef.global(\n    (ScopedHolder scope) =\u003e ModelRepo();\n);\n\nclass ModelRepo {\n    List\u003cModel\u003e getModels({bool withNested = false}) {\n        // request the database\n        // if `withNested` = true, join with the `nestedModel` table\n        throw Unimplemented();\n    }\n}\n\n@Query()\nFutureOr\u003cList\u003cModel\u003e\u003e getModels(Ctx ctx) {\n    final PossibleSelections lookahead = ctx.lookahead();\n    assert(!lookahead.isUnion);\n    final PossibleSelectionsObject lookaheadObj = lookahead.asObject;\n    final withNested = lookaheadObj.contains('nested');\n\n    final ModelRepo repo = modelRepo.get(ctx);\n    return repo.getModels(withNested: withNested);\n}\n\n```\n\nWith this implementation and given the following queries:\n\n```graphql\nquery getModelsWithNested {\n  getModels {\n    id\n    name\n    nested {\n      id\n      name\n    }\n  }\n}\n\nquery getModelsBase {\n  getModels {\n    id\n    name\n  }\n}\n```\n\n`ModelRepo.getModels` will receive `true` in the `withNested` param for the `getModelsWithNested` query since `lookaheadObj.contains('nested')` will be `true`. On the other hand, the `withNested` param will be `false` for the `getModelsBase` query since the \"nested\" field was not selected.\n\nIn this way, `ModelRepo.getModels` knows what nested fields it should return. It could add additional joins in a SQL query, for example.\n\nThe `PossibleSelections` class has the information about all the nested selected fields when the type of the field is a Composite Type (Object, Interface or Union). When it's an Union, it will provide a map from the type name Object variants to the given variant selections. The @skip and @include directives are already taken into account. You can read more about the `PossibleSelections` class in the [source code](https://github.com/juancastillo0/leto/blob/main/leto_schema/lib/src/req_ctx.dart).\n\n## DataLoader (Batching)\n\nThe code in Leto is a port of [graphql/dataloader](https://github.com/graphql/dataloader).\n\nAn easier to implement but probably less performant way of solving the N+1 problem is by using a `DataLoader`. It allows you to batch multiple requests and execute the complete batch in a single function call.\n\n```dart\n\n@GraphQLObject()\nclass Model {\n    final String id;\n    final String name;\n    final int nestedId;\n\n    const Model(this.id, this.name, this.nestedId);\n\n    NestedModel nested(Ctx ctx) {\n        return modelNestedRepo.get(ctx).getNestedModel(nestedId);\n    }\n}\n\nclass NestedModelRepo {\n\n  late final dataLoader = DataLoader.unmapped\u003cString, NestedModel\u003e(getNestedModelsFromIds);\n\n  Future\u003cList\u003cNestedModel\u003e\u003e getNestedModel(String id) {\n    // Batch the id, eventually `dataLoader` will execute\n    // `getNestedModelsFromIds` with a list of batched ids\n    return dataLoader.load(id);\n  }\n\n  Future\u003cList\u003cNestedModel\u003e\u003e getNestedModelsFromIds(List\u003cString\u003e ids) {\n      // Multiple calls to `Model.nested` will be batched and\n      // all ids will be passed in the `ids` argument\n\n      // request the database\n      final List\u003cNestedModel\u003e models = throw Unimplemented();\n\n      // Make a map from id to model instance\n      final Map\u003cString, NestedModel\u003e modelsMap = models.fold(\n        {}, (map, model) =\u003e map..[model.id] = model\n      );\n      // Return the models in the same order as the `ids` argument\n      return List.of(ids.map((id) =\u003e modelsMap[id]!));\n  }\n}\n\nfinal modelNestedRepo = ScopedRef.local(\n    (scope) =\u003e NestedModelRepo()\n);\n\n\n@Query()\nList\u003cModel\u003e getModels(Ctx ctx) {\n    return modelRepo.get(ctx).getModels();\n}\n\n```\n\nThe DataLoader has some options for configuring it. For example you can specify the maximum size of the batch (default: `2^53` or the maximum javascript integer), whether to batch requests or not (default: `true`) and provide a custom batch schedule function, by default it will use `Future.delayed(Duration.zero, executeBatch)`.\n\nYou can also configure caching by providing a custom cache implementation, a custom function that maps the key passed to `DataLoader.load` to the cache's key or disabling caching in the DataLoader.\n\n## Combining LookAhead with DataLoader\n\nYou can use both, LookAhead and DataLoader at the same time. The keys provided to the `DataLoader.load` function can be anything, so you could send the `PossibleSelection` information, for example.\n\n\n# Extensions\n\nExtensions implement additional functionalities to the server's parsing, validation and execution. For example, extensions for tracing ([GraphQLTracingExtension](#apollo-tracing)), logging ([GraphQLLoggingExtension](#logging-extension)), error handling or caching ([GraphQLPersistedQueries](#persisted_queries) and [GraphQLCacheExtension](#response-cache)). All extension implementations can be found in the [extensions](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions) folder in `package:leto`. The main API with all the methods that can be overridden is found in [this file](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/extension.dart).\n\n## Persisted Queries\n\nSave network bandwidth by storing GraphQL documents on the server and not requiring the Client to send the full document String on each request.\n\nMore information: https://www.apollographql.com/docs/apollo-server/performance/apq/\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/persisted_queries.dart)\n\n## Apollo Tracing\n\nTrace the parsing, validation and execution of your GraphQL server to monitor execution times of all GraphQL requests.\n\nMore information: https://github.com/apollographql/apollo-tracing\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/tracing.dart)\n\n## Response Cache\n\nUtility for caching responses in your GraphQL server and client.\n\nClient GQL Link implementation in:\n// TODO: 2E\n\n- Hash: Similar to HTTP If-None-Match and Etag headers. Computes a hash of the payload (sha1 by default) and returns it to the Client when requested. If the Client makes a request with a hash (computed locally or saved from a previous server response), the extension compares the hash and only returns the full body when the hash do not match. If the hash match, the client already has the last version of the payload.\n\n- MaxAge: If passed a `Cache` object, it will save the responses and compare the saved date with the current date, if the maxAge para is greater than the difference, it returns the cached value without executing the field's resolver.\n\n- UpdatedAt: Similar to HTTP If-Modified-Since and Last-Modified headers.\n\n// TODO: 2E retrieve hash, updatedAt and maxAge in resolvers.\n\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/cache_extension.dart)\n\n## Logging Extension\n\nThe logging extension allows you monitor requests and responses executed by your server.\n\nProvides some utilities for printing and retrieving information from execution, logging errors and provides a default `GraphQLLog` class that contains aggregated information about the request.\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/logging_extension.dart)\n\n## Map Error Extension\n\nSimple extension for mapping an error catched on resolver execution. \n\nWith a function that receives the thrown error and some context as parameter and returns a `GraphQLException?`, this extension will override the error and pass it to the executor, which will eventually return it to the user as an error in the response's `errors` list.\n\n[Source code](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/map_error_extension.dart)\n\n## Custom Extensions\n\nTo create a custom extension you can extend [`GraphQLExtension`](https://github.com/juancastillo0/leto/blob/main/leto/lib/src/extensions/extension.dart) and override the necessary functions, all of which are executed throughout a request's parsing, validation and execution.\n\nTo save state scoped to a single request you can use the `ScopedMap.setScoped(key, value)` and retrieve the state in a different method with `final value = ScopedMap.get(key);`. Where the `ScopedMap` can be accessed with `ctx.globals`.\n\nAll extensions are implemented in this way, so you can look at the source code for some examples.\n\n# Directives\n\nFor more information: [GraphQL specification](https://spec.graphql.org/draft/#sec-Type-System.Directives)\n\n\n[`GraphQLDirective`](https://github.com/juancastillo0/leto/blob/main/leto_schema/lib/src/directive.dart) allows you to provide more information about different elements of your schema and queries.\n\nThe default skip, include, deprecated and specifiedBy directives are provided. Fields in the different type system definition classes allow you to include the deprecated reason for fields or enum values, and a url of the specification for scalar types. This information will be printed when using the `printSchema` utility, can be retrieved in Dart through GraphQL extension for modifying the behavior of request execution or, if introspection is enabled, will be exposed by the GraphQL server.\n\nThe skip and include directives are supported during document execution following the spec. Right now, custom directives on execution can be obtained by using the parsed `DocumentNode` from package:gql, in the future better support could be implemented.\n\nProvide custom directives supported by your server through the \n`GraphQLSchema.directives` field.\n\nYou can retrieve custom directives values in your GraphQL Schema definition when using the `buildSchema` utility, which will parse all directives and leave them accessible through the `astNode` Dart fields in the different GraphQL elements. Setting custom directives values through the GraphQL Schema Dart classes is a work in progress. Right now, you can add `DirectiveNode`s to the element's [attachments](#attachments) if you want to print it with `printSchema`, however the API will probably change. See https://github.com/graphql/graphql-js/issues/1343\n\n## `KeyDirective`\n\nSpecifies that a given Object can be identified by the fields\npassed as argument to the directive\n\nIt is repeatable, there can be multiple keys per Object.\n\nThe following example shows an Object that can be identified by two keys,\nthe \"id\" field and the combination \"type\" and \"nested.value\" fields.\n\n```graphql\ntype Model @key(fields: \"id\") @key(fields: \"type nested { value } \") {\n  id: String!\n  type: String!\n  nested {\n    value: int!\n  }\n}\n```\n\n## `ValidaDirective`\n\nUsing `package:valida`, the valida directive represents the validation configuration. At the moment the `ValidaField` annotation over arguments and input fields is used to populated the valida directive. For example, the following annotated `GraphQLInput` that verifies that all lengths inside the `strs` field have at least 1 byte length:\n\n\u003c!-- include{generator-valida-arg-model} --\u003e\n```dart\n@Valida()\n@GraphQLInput()\nclass ValidaArgModel {\n  @ValidaList(each: ValidaString(minLength: 1))\n  final List\u003cString\u003e strs;\n  final ValidaArgModel? inner;\n\n  ValidaArgModel({\n    required this.strs,\n    this.inner,\n  });\n\n  Map\u003cString, Object?\u003e toJson() {\n    return {\n      'strs': strs,\n      'inner': inner?.toJson(),\n    };\n  }\n\n  factory ValidaArgModel.fromJson(Map\u003cString, Object?\u003e map) {\n    return ValidaArgModel(\n      strs: List\u003cString\u003e.from(map['strs']! as List),\n      inner: map['inner'] != null\n          ? ValidaArgModel.fromJson((map['inner']! as Map).cast())\n          : null,\n    );\n  }\n}\n```\n\u003c!-- include-end{generator-valida-arg-model} --\u003e\n\nWill generate the following GraphQL definition with valida directive.\n\n\u003c!-- include{generator-valida-arg-model-graphql} --\u003e\n```graphql\ninput ValidaArgModel {\n  strs: [String!]! @valida(jsonSpec: \"\"\"\n{\"variantType\":\"list\",\"each\":{\"variantType\":\"string\",\"minLength\":1}}\n\"\"\")\n  inner: ValidaArgModel\n}\n```\n\u003c!-- include-end{generator-valida-arg-model-graphql} --\u003e\n\n\nIn this case the JSON '{\"variantType\":\"list\",\"each\":{\"variantType\":\"string\",\"minLength\":1}}' is the result of executing the annotation's (`ValidaList(each: ValidaString(minLength: 1))`) toJson method.\n\n# Attachments\n\nThis API is experimental.\n\nAll GraphQL elements in the schema can have addition custom attachments. This can be used by other libraries or extensions to change the behavior of execution. For example, for supporting custom input validations or configuring the max age for some fields in an extension that caches responses.\n\n## AttachmentWithValidation\n\nAn attachment can register validation logic by implementing `AttachmentWithValidation`. The required validation method `validateElement` will be executed when the GraphQLSchema is validated, as an argument it will receive the Schema validation context and the `GraphQLElement` associated with the attachment.\n\n## ToDirectiveValue\n\nImplementing this interface allows the GraphQLSchema's SDL String to contain the attachment's information by adding directives over the specific element associated with the attachment. Attachments that implement `ToDirectiveValue` require the following getters:\n\n```dart\n  /// The directive value represented by this object\n  DirectiveNode get directiveValue;\n\n  /// The directive definition of the [directiveValue]\n  GraphQLDirective get directiveDefinition;\n```\n\n---\n\nWe provide two attachments, both of which implement `AttachmentWithValidation` and `ToDirectiveValue`.\n\n### `KeyAttachment`\n\nImplements the [key directive](#keydirective) over a given object. The `fields` String is required.\n\n### `ValidaAttachment`\n\nImplements the [valida directive](#validadirective) over a given input field or argument. The `annotation` argument should be the `ValidaField` specified for the element. You probably should use it manually, when using code generation the validation will be performed for any `@Valida()` annotated class or resolver and the attachment will be placed at the appropriate location.\n\n## Usage\n\nTo use associate a GraphQLElement (type, field or directive) with attachments, you may pass them as arguments to each of the GraphQLElements constructor.\n\n### AttachFn for code generation\n\nTo add attachments to types or fields when using code generation you can use the `AttachFn` decorator. An example of this is the following, using the [`KeyAttachment`](#keyattachment) for [`KeyDirective`](#keydirective) and the [`ValidaAttachment`](#validaattachment) for [`ValidaDirective`](#validadirective) (which is set up in the generated code).\n\n\u003c!-- include{generator-attachments} --\u003e\n```dart\n@Valida()\n@AttachFn(KeyedAttachment.attachments)\n@GraphQLObject()\nclass KeyedAttachment {\n  final String id;\n  final String name;\n  @ValidaDate(max: 'now')\n  final DateTime createdAt;\n  final NestedAttachment nested;\n\n  KeyedAttachment({\n    required this.id,\n    required this.name,\n    required this.createdAt,\n    required this.nested,\n  });\n\n  static List\u003cAttachmentWithValidation\u003e attachments() {\n    return const [\n      KeyAttachment('id'),\n      KeyAttachment('name nested {id}'),\n    ];\n  }\n}\n\n@AttachFn(NestedAttachment.attachments)\n@GraphQLObject()\nclass NestedAttachment {\n  final int id;\n\n  NestedAttachment({\n    required this.id,\n  });\n\n  static List\u003cAttachmentWithValidation\u003e attachments() {\n    return const [\n      KeyAttachment('id'),\n    ];\n  }\n}\n```\n\u003c!-- include-end{generator-attachments} --\u003e\n\nWill generate the following GraphQL schema:\n\n\u003c!-- include{generator-attachments-graphql} --\u003e\n```graphql\ntype KeyedAttachment @key(fields: \"id\") @key(fields: \"name nested {id}\") {\n  id: ID!\n  name: String!\n  createdAt: Date! @valida(jsonSpec: \"\"\"\n{\"variantType\":\"date\",\"max\":\"now\"}\n\"\"\")\n  nested: NestedAttachment!\n}''',\n  '''\ntype NestedAttachment @key(fields: \"id\") {\n  id: Int!\n```\n\u003c!-- include-end{generator-attachments-graphql} --\u003e\n\n\n# Utilities\n\nMost GraphQL utilities can be found in the [`utilities`](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/utilities) folder in package:leto_schema.\n\n### [`buildSchema`](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/utilities/build_schema.dart)\n\nCreate a `GraphQLSchema` from a GraphQL Schema Definition (SDL) document String.\n\n### [`printSchema`](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/utilities/print_schema.dart)\n\nTransform a `GraphQLSchema` into a String in the GraphQL Schema Definition Language (SDL).\n\n\n### [`extendSchema`](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/utilities/extend_schema.dart)\n\nExperimental. Extend a `GraphQLSchema` with an SDL document. This will return an extended `GraphQLSchema` with the additional types, fields, inputs and directives provided in the document.\n\n### [`introspectionQuery`](https://github.com/juancastillo0/leto/tree/main/leto_schema/lib/src/utilities/introspection_query.dart)\n\nCreate an introspection document query for retrieving Schema information from a GraphQL server.\n\n### [`mergeSchemas`](https://github.com/juancastillo0/leto/blob/main/leto_shelf/example/lib/schema/graphql_utils.dart)\n\nExperimental. Merge multiple `GraphQLSchema`. The output `GraphQLSchema` contains all the query, mutations and subscription fields from the input schemas. Nested objects are also merged.\n\n\n### [`schemaFromJson`](https://github.com/juancastillo0/leto/blob/main/leto_shelf/example/lib/schema/schema_from_json.dart)\n\nExperimental. Build a GraphQLSchema from a JSON value, will add query, mutation, subscription and custom events on top of the provided JSON value. Will try to infer the types from the JSON structure.\n\n\n# Contributing\n\nThanks for considering making a contribution! Every issue or question helps!\n\nThis package uses [melos](https://github.com/invertase/melos) to manage dependencies. To install it run:\n\n```bash\npub global activate melos\n```\n\nThen, to link the local packages run:\n\n```bash\nmelos bootstrap\n```\n\nIf using fvm, you may need to run:\n\n```bash\nfvm flutter pub global run melos bootstrap\n```\n\nYou can view most of the commands that you will need in the [`melos.yaml` file](./melos.yaml). However, melos can be used to do other stuff like executing any command you want using `melos exec`, for more information please view the [melos Github repo](https://github.com/invertase/melos).\n\n## Scripts\n\nThe following scripts are used in CI and can be used thought development. At the moment, both of them are related to generating documentation.\n### [`collect_examples.dart`](./scripts/collect_examples.dart)\n\nThis script allows you to include documentation in the README files (or any Markdown file) from comments in Dart code. In the future, we will probably support sharing documentation between Dart files.\n\nFor example, by placing this comment annotations in a section of a Dart file:\n\n```dart\n// @example-start{name-of-example,extension:graphql,start:1,end:-2}\nconst graphQLTypeSection = '''\ntype ObjectName {\n  objectField: String\n}\n''';\n// @example-end{name-of-example}\n```\n\nAnd adding this comment in the Markdown (`.md`) file:\n\n```markdown\n\u003c!-- include{name-of-example} --\u003e\n```\n\nYou can copy the same Dart snippet by executing `dart run script/collect_examples.dart`. The Markdown file will be updated to:\n\n~~~markdown\n\u003c!-- include{name-of-example} --\u003e\n```graphql\ntype ObjectName {\n  objectField: String\n}\n```\n\u003c!-- include-end{name-of-example} --\u003e\n~~~\n\nYou can find many examples in the [source code of this README](https://raw.githubusercontent.com/juancastillo0/leto/main/README.md) with Dart examples annotated through out the repository's Dart files.\n\nThe scripts has a couple of arguments, in particular `--check` is used in CI to verify the the code snippets are synchronized between the Dart files and Markdown files. `--generate-dart-file` will generate Dart code with the snippet Strings and `--generate-md-dir` will generate one `.md` file for each example within the directory passed as argument.\n\n### [`generate_docusaurus.dart`](./scripts/generate_docusaurus.dart)\n\nGenerates the Docusaurus documentation page. Basically, it copies the README file sections into the `/docusaurus/docs/` directory in a format that Docusaurus understands. This is used in CI to build the [documentation page](https://juancastillo0.github.io/leto).\n\nSmall pieces of configuration can be included within the README files. For example, to assign tags to a section (which will be converted to a page, perhaps `/docs/leto_shelf/section-title` if it is in `leto_shelf`'s README) you can use.\n\n```markdown\n# Section Title \u003c!-- docusaurus{\"tags\":[\"tagName1\",\"tagName2\"]} --\u003e\n```\n\nThe content with the brackets should be a JSON string.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuancastillo0%2Fleto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuancastillo0%2Fleto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuancastillo0%2Fleto/lists"}