Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to improve doc. of execution-pipline.md by correcting and... #497

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 32 additions & 32 deletions docs/execution-pipeline.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,59 @@

Technical overview over execution pipeline
Server execution pipeline
======================

The major work done by FSharp.Data.GraphQL server can be split into several phases:
The major work done by FSharp.Data.GraphQL.Server consists of the following phases:

1. Compilation phase, which is executed once when a new `Schema` is being created.
2. Planning phase, when GraphQL query string has been supplied.
3. Execution phase, when query is being executed and result is produced.
1. Compilation phase: when a new `Schema` is being created;
2. Planning phase: when a GraphQL query as a raw string has been supplied;
3. Execution phase: when a query is being executed and a result is produced

## Compilation phase

Compilation phase is called, when we're creating a new schema instance. From this point, all types defined within that schema should remain unchanged. During this step, server will invoke all operations that can be done ahead of time, before actual queries can be handled. This also means that creating a new schema is expensive process, and **should not** be done on each request.
The compilation phase is when we're creating a new schema instance. After the schema is created, all types defined within that schema will remain unchanged. Also during this phase, the server will invoke all operations that can be done independent of any future query. Creating a new schema is an expensive process which is independent of any request and therefore **should not** be done on each request.

Compilation phase performs several operations:
During the compilation phase, basically the following operations are performed:

- Validates, if all type definitions conform GraphQL specification.
- Creates an [introspection](https://facebook.github.io/graphql/#sec-Introspection)-oriented representation of the schema.
- Prepares value resolution pipeline for each of the fields defined in the schema.
- Validation that all type definitions conform to the GraphQL specification;
- Creation of an [introspection](https://facebook.github.io/graphql/#sec-Introspection)-oriented representation of the schema;
- Preparation of a value resolution pipeline for each of the fields defined in the schema.

## Planning phase

In many cases planning and execution phases are called together. This however can be changed by calling `schema.CreateExecutionPlan(graphQlQueryString)`, which produces so-called `ExecutionPlan` without actually executing a query.
In many cases, it makes sense to handle planning and execution phases sequentially as one big phase. However, one can handle them separately by calling `schema.CreateExecutionPlan(graphQlQueryString)`, which produces a so-called `ExecutionPlan` without actually executing a query.

As the name suggests, `ExecutionPlan` and its components (a tree of objects known as `ExecutionInfo`s) describes how the query is going to be executed. This includes:

- Inlining GraphQL query fragments.
- Defining fields resolution strategy - serial or parallel.
- Combining information from query AST (resolved fields / aliases) with server-side information about them (field and type definitions).
- Preparation of the hooks in the execution chain, that will be supplied with potential variables upon execution.
- Inlining GraphQL query fragments;
- Defining fields resolution strategy - sequential or parallel;
- Combining information from the query AST (resolved fields / aliases) with server-side information about them (field and type definitions);
- Preparation of the hooks in the execution chain that will be supplied with potential variables upon execution.

Spliting planning and execution phases is a good idea, when you have the same GraphQL query requested many times (with potentially different variables). This way you can compute execution plan once and cache it. You can use `executionPlan.DocumentId` as a cache identifier. DocumentId is also returned as one of the top level fields in GraphQL response, so it can be used from the client side. Other GraphQL implementations describe that technique as **persistent queries**.
Spliting planning and execution phases is a good idea when you have the same GraphQL query requested many times (with potentially different variables). This way you can compute the execution plan once and cache it. You can use `executionPlan.DocumentId` as a cache identifier. DocumentId is also returned as one of the top level fields in GraphQL response, so it can be used from the client side. Other GraphQL implementations describe that technique as **persistent queries**.

## Execution phase

Execution phase is performed, when we want to resolve response from GraphQL server given query execution plan and optional set of variables provided by the client. Usually it's called together with planning phase descibed above.
The execution phase is performed when we want to resolve a response from an GraphQL server given a query execution plan and an optional set of variables provided by the client. Usually it's called together with the planning phase descibed above.

During execution phase, we perform a traversal over execution plan tree, create an execution context objects for each of the fields and supply them along with data resolved from previous higher level resolver responses recrusively.
During execution phase, we perform a traversal of the execution plan tree; create execution context objects for each of the fields and supply them along with data resolved from previous higher level resolver responses recursively.

Field resolution context contains all of the necessary metadata about things such as:
A field resolution context contains metadata such as:

- Executing schema itself.
- Variables provided with the request.
- Field parameters (in case if field defined any arguments).
- Type definition of both parent and expected return type.
- ExecutionInfo which is fragment of the execution plan itself related to current field and all of its subsequent fields.
- Information about the execution of the schema itself;
- Variables provided with the request;
- Field parameters (in case the corresponding field defined any arguments);
- Type definition of both parent and expected return type;
- `ExecutionInfo` which is a fragment of the execution plan itself related to the current field and all of its subsequent fields.

Execution phase can be performed using one of the two strategies:
The execution phase can be performed using one of the two strategies:

- **Parallel**, where asynchronous fields can be resolved in unordered manner. This is default option in case of GraphQL queries due to fact, that they are readonly operations.
- **Sequential** where asynchronous fields must be resolved in correct order (as it was defined in query string). This is default mode for GraphQL mutations.
- **Parallel**: in which asynchronous fields can be resolved in any order. This is the default mode for GraphQL queries due to the fact that they are readonly operations.
- **Sequential**: in which asynchronous fields must be resolved in a specific order: as it was defined in the query. This is default mode for GraphQL mutations.

As result of GraphQL query execution, a dictionary with resolved values will be returned. It contains following fields:
The result of a GraphQL query execution is a dictionary with resolved values. This dictionary contains the following fields:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, now it is a GQLResponse object

type GQLResponse =
    { DocumentId: int
      Data : Output Skippable
      Errors : GQLProblemDetails list Skippable }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The result of a GraphQL query execution is a dictionary with resolved values. This dictionary contains the following fields:
The result of a GraphQL query execution is a `GQLResponse` object with the following fields:


- `documentId` which is query AST document hash code - it can be used to implement execution plan caching.
- `data` with a formated GraphQL response matching the requested query string.
- `errors` entry is optional. If it has been provided, it will contain list of errors, that occured during query execution.
- `documentId`: which is the hash code of the query's AST document - it can be used to implement execution plan caching (persistent queries).
- `data`: with a formated GraphQL response matching the requested query.
- `errors`: optional. If it has been provided, it will contain a list of errors that occured during query execution.
Comment on lines +55 to +57
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `documentId`: which is the hash code of the query's AST document - it can be used to implement execution plan caching (persistent queries).
- `data`: with a formated GraphQL response matching the requested query.
- `errors`: optional. If it has been provided, it will contain a list of errors that occured during query execution.
- `documentId`: which is the hash code of the query's AST document - it can be used to implement execution plan caching (persistent queries).
- `data`: optional, a formatted GraphQL response matching the requested query (`KeyValuePair seq`). Absent in case of an error that does not allow continuing processing and returning any GraphQL results.
- `errors`: optional, contains a list of errors (`GQLProblemDetails`) that occurred during query execution.


This result can be serialized directly and returned to the client.
This result can then be serialized and returned to the client.