diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66b9bfe4a..fbf0028d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,17 +3,17 @@
## 0.2.0 (UNRELEASED)
- Removed support for Python 3.5 and added support for 3.7.
-- Moved to `GraphQL-core-next` that supports `async` resolvers, query execution and implements more recent version of GraphQL spec. If you are updating existing project, you will need to uninstall `graphql-core` before installing `graphql-core-next`, as both libraries use `graphql` namespace.
+- Moved to `GraphQL-core-next` that supports `async` resolvers, query execution and implements a more recent version of GraphQL spec. If you are updating an existing project, you will need to uninstall `graphql-core` before installing `graphql-core-next`, as both libraries use `graphql` namespace.
- Added `gql()` utility that provides GraphQL string validation on declaration time, and enables use of [Apollo-GraphQL](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) plugin in Python code.
-- Added `load_schema_from_path()` utility function that loads GraphQL types from file or directory containing `.graphql` files, also performing syntax validation.
-- Added `start_simple_server()` shortcut function for a quick dev server creation, abstracting away the `GraphQLMiddleware.make_server()` from first time users.
+- Added `load_schema_from_path()` utility function that loads GraphQL types from a file or directory containing `.graphql` files, also performing syntax validation.
+- Added `start_simple_server()` shortcut function for quick dev server creation, abstracting away the `GraphQLMiddleware.make_server()` from first time users.
- `Boolean` built-in scalar now checks the type of each serialized value. Returning values of type other than `bool`, `int` or `float` from a field resolver will result in a `Boolean cannot represent a non boolean value` error.
-- Redefining type in `type_defs` will now result in `TypeError` being raised. This is breaking change from previous behaviour where old type was simply replaced with new one.
-- Returning `None` from scalar `parse_literal` and `parse_value` function no longer results in GraphQL API producing default error message. Instead `None` will be passed further down to resolver or producing "value is required" error if its marked as such with `!` For old behaviour raise either `ValueError` or `TypeError`. See documentation for more details.
+- Redefining type in `type_defs` will now result in `TypeError` being raised. This is a breaking change from previous behavior where the old type was simply replaced with a new one.
+- Returning `None` from scalar `parse_literal` and `parse_value` function no longer results in GraphQL API producing default error message. Instead, `None` will be passed further down to resolver or produce a "value is required" error if its marked as such with `!` For old behavior raise either `ValueError` or `TypeError`. See documentation for more details.
- `resolvers` argument defined by `GraphQLMiddleware.__init__()`, `GraphQLMiddleware.make_server()` and `start_simple_server()` is now optional, allowing for quick experiments with schema definitions.
-- `dict` has been removed as primitive for mapping python function to fields. Instead, `make_executable_schema()` expects object or iterable of objects with `bind_to_schema` method, that is called with `GraphQLSchema` instance and are expected to add resolvers to schema.
-- Default resolvers are no longer set implicitly by `make_executable_schema()`. Instead you expected to include either `ariadne.fallback_resolvers` or `ariadne.snake_case_fallback_resolvers` in the list of `resolvers` for your schema.
+- `dict` has been removed as primitive for mapping python function to fields. Instead, `make_executable_schema()` expects object or list of objects with a `bind_to_schema` method, that is called with a `GraphQLSchema` instance and are expected to add resolvers to schema.
+- Default resolvers are no longer set implicitly by `make_executable_schema()`. Instead you are expected to include either `ariadne.fallback_resolvers` or `ariadne.snake_case_fallback_resolvers` in the list of `resolvers` for your schema.
- Added `snake_case_fallback_resolvers` that populates schema with default resolvers that map `CamelCase` and `PascalCase` field names from schema to `snake_sase` names in Python.
- Added `ResolverMap` object that enables assignment of resolver functions to schema types.
- Added `Scalar` object that enables assignment of `serialize`, `parse_value` and `parse_literal` functions to custom scalars.
-- Both `ResolverMap` and `Scalar` are validating if schema defines specified types and/or fields at moment of creation of executable schema, providing better feedback to developer.
+- Both `ResolverMap` and `Scalar` are validating if schema defines specified types and/or fields at the moment of creation of executable schema, providing better feedback to the developer.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e7816bd87..b3aaf6ecf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,36 +2,36 @@
Thank you for your interest in contributing to Ariadne!
-We welcome bug reports, questions, pull requests and general feedback.
+We welcome bug reports, questions, pull requests, and general feedback.
-We also ask all contributors to familiarize themselves with and follow project's code of conduct, available in [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) file kept in repository's main directory.
+We also ask all contributors to familiarize themselves with and follow project's code of conduct, available in the [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) file kept in the repository's main directory.
# Reporting bugs, asking for help, offering feedback and ideas
-You can use [GitHub issues](https://github.com/mirumee/ariadne/issues) to report bugs, ask for help, share your ideas or simply offer feedback. We are curious what you are thinking about Ariadne!
+You can use [GitHub issues](https://github.com/mirumee/ariadne/issues) to report bugs, ask for help, share your ideas, or simply offer feedback. We are curious what you think of Ariadne!
## Development setup
Ariadne is written to support Python 3.6 and 3.7.
-Codebase is formatted using [Black](https://github.com/ambv/black), and contents of `ariadne` package are annotated with types and validated using [mypy](http://mypy-lang.org/index.html).
+Codebase is formatted using [Black](https://github.com/ambv/black), and the contents of the `ariadne` package are annotated with types and validated using [mypy](http://mypy-lang.org/index.html).
Tests are developed using [pytest](https://pytest.org/) with [Codecov](https://codecov.io/gh/mirumee/ariadne) for monitoring coverage.
Dev requirements can be installed using `requirements-dev.txt`.
-We require for all changes to be done via pull requests, and to be approved by member-ranked users before merging.
+We require all changes to be done via pull requests, and to be approved by member-ranked users before merging.
## Working on issues
-We consider all issues not assigned to anybody as available for contributors. The **[help wanted](https://github.com/mirumee/ariadne/labels/help%20wanted)** label is used to single out issues that we consider easier or higher priority on list of things that we would like to see.
+We consider all issues which are not assigned to anybody as being available for contributors. The **[help wanted](https://github.com/mirumee/ariadne/labels/help%20wanted)** label is used to single out issues that we consider easier or higher priority on the list of things that we would like to see.
-If you've found issue you want to help with, please add your comment to it - this lets other contributors know what issues are being worked on, as well as for maintainers to offer guidance and help.
+If you've found issue you want to help with, please add your comment to it - this lets other contributors know what issues are being worked on, as well as allowing maintainers to offer guidance and help.
## Pull requests
-We don't require that pull requests to be followed with bug reports. If you've found typo or silly little bug that has no issue or pull request already, you can open your own pull request. We only ask that this PR provides context or explanation for what problem it fixes or which are of project it improves.
\ No newline at end of file
+We don't require pull requests to be followed with bug reports. If you've found a typo or a silly little bug that has no issue or pull request already, you can open your own pull request. We only ask that this PR provides context or explanation for what problem it fixes, or which area of the project it improves.
\ No newline at end of file
diff --git a/README.md b/README.md
index d4b2f9a09..4ee83902d 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
Ariadne is a Python library for implementing [GraphQL](http://graphql.github.io/) servers, inspired by [Apollo Server](https://www.apollographql.com/docs/apollo-server/) and built with [GraphQL-core-next](https://github.com/graphql-python/graphql-core-next).
-Currently the library already implements enough features to enable developers to build functional GraphQL APIs. It is also being dogfooded internally at number of projects.
+The library already implements enough features to enable developers to build functional GraphQL APIs. It is also being dogfooded internally on a number of projects.
Documentation is available [here](https://ariadne.readthedocs.io/en/latest/?badge=latest).
@@ -24,7 +24,7 @@ Ariadne can be installed with pip:
## Quickstart
-Following example creates API defining `Person` type and single query field `people` returning list of two persons. It also starts local dev server with [GraphQL Playground](https://github.com/prisma/graphql-playground) available on the `http://127.0.0.1:8888` address.
+The following example creates an API defining `Person` type and single query field `people` returning a list of two persons. It also starts a local dev server with [GraphQL Playground](https://github.com/prisma/graphql-playground) available on the `http://127.0.0.1:8888` address.
```python
from ariadne import ResolverMap, gql, start_simple_server
@@ -72,6 +72,6 @@ For more guides and examples, please see the [documentation](https://ariadne.rea
Contributing
------------
-We are welcoming contributions to Ariadne! If you've found a bug, issue, got question or just want to drop general feedback, feel free to use [GitHub issues](https://github.com/mirumee/ariadne/issues).
+We are welcoming contributions to Ariadne! If you've found a bug or issue, or if you have any questions or feedback, feel free to use [GitHub issues](https://github.com/mirumee/ariadne/issues).
For guidance and instructions, please see [CONTRIBUTING.md](CONTRIBUTING.md).
diff --git a/docs/custom-server.rst b/docs/custom-server.rst
index c4d6be1bd..87d3c022a 100644
--- a/docs/custom-server.rst
+++ b/docs/custom-server.rst
@@ -1,7 +1,7 @@
Custom server example
=====================
-In addition to simple GraphQL server implementation in form of ``GraphQLMiddleware``, Ariadne provides building blocks for assembling custom GraphQL servers.
+In addition to simple a GraphQL server implementation in the form of ``GraphQLMiddleware``, Ariadne provides building blocks for assembling custom GraphQL servers.
Creating executable schema
diff --git a/docs/introduction.rst b/docs/introduction.rst
index f7a174532..39bdb1733 100644
--- a/docs/introduction.rst
+++ b/docs/introduction.rst
@@ -13,11 +13,11 @@ Make sure that you've installed Ariadne using ``pip install ariadne``, and that
Defining schema
---------------
-First, we will with describe what data can be obtained from our API.
+First, we will describe what data can be obtained from our API.
In Ariadne this is achieved by defining Python strings with content written in `Schema Definition Language `_ (SDL), a special language for declaring GraphQL schemas.
-We will start with defining the special type ``Query`` that GraphQL services use as entry point for all reading operations. Next we will specify a single field on it, named ``hello``, and define that it will return a value of type ``String``, and that it will never return ``null``.
+We will start by defining the special type ``Query`` that GraphQL services use as entry point for all reading operations. Next, we will specify a single field on it, named ``hello``, and define that it will return a value of type ``String``, and that it will never return ``null``.
Using the SDL, our ``Query`` type definition will look like this::
@@ -27,13 +27,13 @@ Using the SDL, our ``Query`` type definition will look like this::
}
"""
-The ``type Query { }`` block declares the type, ``hello`` is the field definition, ``String`` is the return value type, and the exclamation mark following it means that returned value will never be ``null``.
+The ``type Query { }`` block declares the type, ``hello`` is the field definition, ``String`` is the return value type, and the exclamation mark following it means that the returned value will never be ``null``.
Validating schema
-----------------
-Ariadne provides tiny ``gql`` utility function that takes single argument: GraphQL string, validates it and raises descriptive ``GraphQLSyntaxError``, or returns original unmodified string if its correct::
+Ariadne provides tiny ``gql`` utility function that takes single argument: GraphQL string, validates it and raises descriptive ``GraphQLSyntaxError``, or returns the original unmodified string if its correct::
from ariadne import gql
@@ -43,7 +43,7 @@ Ariadne provides tiny ``gql`` utility function that takes single argument: Graph
}
""")
-If we try to run above code now, we will get an error pointing to our incorrect syntax within our ``type_defs`` declaration::
+If we try to run the above code now, we will get an error pointing to our incorrect syntax within our ``type_defs`` declaration::
graphql.error.syntax_error.GraphQLSyntaxError: Syntax Error: Expected :, found Name
@@ -53,7 +53,7 @@ If we try to run above code now, we will get an error pointing to our incorrect
^
}
-Using ``gql`` is optional, but without it above error would occur during your server's initialization and point to somewhere inside Ariadne's GraphQL initialization logic, making tracking down incorrect place trickier if your API is large and spread across many modules.
+Using ``gql`` is optional; however, without it, the above error would occur during your server's initialization and point to somewhere inside Ariadne's GraphQL initialization logic, making tracking down the error tricky if your API is large and spread across many modules.
Resolvers
@@ -63,31 +63,31 @@ The resolvers are functions mediating between API consumers and the application'
We want our API to greet clients with a "Hello (user agent)!" string. This means that the ``hello`` field has to have a resolver that somehow finds the client's user agent, and returns a greeting message from it.
-At its simplest, resolver is a function that returns value::
+At its simplest, resolver is a function that returns a value::
def resolve_hello(*_):
return "Hello..." # What's next?
-The above code is perfectly valid, minimal resolver meeting the requirements of our schema. It takes any arguments, does nothing with them and returns blank greeting string.
+The above code is perfectly valid, with a minimal resolver meeting the requirements of our schema. It takes any arguments, does nothing with them and returns a blank greeting string.
Real-world resolvers are rarely that simple: they usually read data from some source such as a database, process inputs, or resolve value in the context of a parent object. How should our basic resolver look to resolve a client's user agent?
In Ariadne every field resolver is called with at least two arguments: ``obj`` parent object, and the query's execution ``info`` that usually contains the ``context`` attribute that is GraphQL's way of passing additional information from the application to its query resolvers.
-Default GraphQL server implementation provided by Ariadne defines ``info.context`` as Python ``dict`` containing a single key named ``environ`` containing basic request data. We can use this in our resolver::
+The default GraphQL server implementation provided by Ariadne defines ``info.context`` as Python ``dict`` containing a single key named ``environ`` containing basic request data. We can use this in our resolver::
def resolve_hello(_, info):
request = info.context["environ"]
user_agent = request.get("HTTP_USER_AGENT", "guest")
return "Hello, %s!" % user_agent
-Notice that we are discarding the first argument in our resolver. This is because ``resolve_hello`` is special type of resolver: it belongs to a field defined on a root type (`Query`), and such fields, by default, have no parent that could be passed to their resolvers. This type of resolver is called a *root resolver*.
+Notice that we are discarding the first argument in our resolver. This is because ``resolve_hello`` is a special type of resolver: it belongs to a field defined on a root type (`Query`), and such fields, by default, have no parent that could be passed to their resolvers. This type of resolver is called a *root resolver*.
Now we need to map our resolver to the ``hello`` field of type ``Query``. To do this, we will use the ``ResolverMap`` class that maps resolver functions to types in the schema. First, we will update our imports::
from ariadne import ResolverMap, gql
-Next, we will create an resolver map for our only type - ``Query``::
+Next, we will create a resolver map for our only type - ``Query``::
# Create ResolverMap for Query type defined in our schema...
query = ResolverMap("Query")
@@ -104,9 +104,9 @@ Next, we will create an resolver map for our only type - ``Query``::
Testing the API
---------------
-Now we have everything we need to finish our API, with only piece missing being the http server that would receive the HTTP requests, execute GraphQL queries and return responses.
+Now we have everything we need to finish our API, with the missing only piece being the http server that would receive the HTTP requests, execute GraphQL queries and return responses.
-This is where Ariadne comes into play. One of the utilities that Ariadne provides is a ``start_simple_server`` that enables developers to experiment with GraphQL locally without need for full-fledged HTTP stack or web framework::
+This is where Ariadne comes into play. One of the utilities that Ariadne provides is a ``start_simple_server`` that enables developers to experiment with GraphQL locally without the need for a full-fledged HTTP stack or web framework::
from ariadne import start_simple_server
@@ -114,9 +114,9 @@ We will now call ``start_simple_server`` with ``type_defs`` and ``query`` as its
start_simple_server(type_defs, query)
-Run your script with ``python myscript.py`` (remember to replace ``myscript.py`` with name of your file!). If all is well, you will see a message telling you that simple GraphQL server is running on the http://127.0.0.1:8888. Open this link in your web browser.
+Run your script with ``python myscript.py`` (remember to replace ``myscript.py`` with the name of your file!). If all is well, you will see a message telling you that the simple GraphQL server is running on the http://127.0.0.1:8888. Open this link in your web browser.
-You will see the GraphQL Playground, the open source API explorer for GraphQL APIs. You can enter ``{ hello }`` query on the left, press the big bright "run" button, and see the result on the right:
+You will see the GraphQL Playground, the open source API explorer for GraphQL APIs. You can enter ``{ hello }`` query on the left, press the big, bright "run" button, and see the result on the right:
.. image:: _static/hello-world.png
:alt: Your first Ariadne GraphQL in action!
diff --git a/docs/modularization.rst b/docs/modularization.rst
index 95da940ee..014e0c0dd 100644
--- a/docs/modularization.rst
+++ b/docs/modularization.rst
@@ -58,13 +58,13 @@ Because Ariadne expects ``type_defs`` to be either string or list of strings, it
start_simple_server([query, user, scalars])
-The order in which types are definer or passed to ``type_defs`` doesn't matter, even if those types depend on each other.
+The order in which types are defined or passed to ``type_defs`` doesn't matter, even if those types depend on each other.
Defining resolver maps in multiple modules
------------------------------------------
-Just like ``type_defs`` can be a string or list of strings, ``resolvers`` can be single resolver map instance, or list of resolver maps::
+Just like ``type_defs`` can be a string or list of strings, ``resolvers`` can be a single resolver map instance, or a list of resolver maps::
from ariadne import ResolverMap, Scalar
@@ -79,7 +79,7 @@ Just like ``type_defs`` can be a string or list of strings, ``resolvers`` can be
start_simple_server(schema, [query, user, datetime_scalar, date_scalar])
-The order in which objects are passed to ``resolvers`` argument matters. ``ResolverMap`` and ``Scalar`` objects replace previously bound resolvers with new ones, when more than one is defined for same GraphQL type.
+The order in which objects are passed to the ``resolvers`` argument matters. ``ResolverMap`` and ``Scalar`` objects replace previously bound resolvers with new ones, when more than one is defined for the same GraphQL type.
Fallback resolvers are safe to put anywhere in the list, because those explicitly avoid replacing already set resolvers.
@@ -106,4 +106,4 @@ Reusing resolver functions
reseller = ResolverMap("Reseller")
reseller.field("email", resolver=resolve_email)
-Note that if you are mixing other decorators with Ariadne's ``@type.field`` syntax, order of decorators will matter.
\ No newline at end of file
+Note that if you are mixing other decorators with Ariadne's ``@type.field`` syntax, the order of decorators will matter.
\ No newline at end of file
diff --git a/docs/mutations.rst b/docs/mutations.rst
index aee97b99d..58234b189 100644
--- a/docs/mutations.rst
+++ b/docs/mutations.rst
@@ -8,13 +8,13 @@ Enter the ``Mutation`` type, ``Query``'s sibling that GraphQL servers use to imp
.. note::
Because there is no restriction on what can be done inside resolvers, technically there's nothing stopping somebody from making ``Query`` fields act as mutations, taking inputs and executing state-changing logic.
- In practice such queries break the contract with client libraries such as Apollo-Client that do client-side caching and state management, resulting in non-responsive controls or inaccurate information being displayed in the UI as the library displays cached data before redrawing it to display an actual response from the GraphQL.
+ In practice, such queries break the contract with client libraries such as Apollo-Client that do client-side caching and state management, resulting in non-responsive controls or inaccurate information being displayed in the UI as the library displays cached data before redrawing it to display an actual response from the GraphQL.
Defining mutations
------------------
-Lets define the basic schema that implements a simple authentication mechanism allowing the client to see if they are authenticated, and to log in and log out::
+Let's define the basic schema that implements a simple authentication mechanism allowing the client to see if they are authenticated, and to log in and log out::
type_def = """
type Query {
@@ -37,7 +37,7 @@ In this example we have the following elements:
Writing resolvers
-----------------
-Mutation resolvers are no different than resolvers used by other types. They are functions that take ``parent`` and ``info`` arguments, as well as any mutation's arguments as keyword arguments. They then return data that should be sent to client as a query result::
+Mutation resolvers are no different than resolvers used by other types. They are functions that take ``parent`` and ``info`` arguments, as well as any mutation's arguments as keyword arguments. They then return data that should be sent to the client as a query result::
def resolve_login(_, info, username, password):
request = info.context["request"]
@@ -68,7 +68,7 @@ Because ``Mutation`` is a GraphQL type like others, you can map resolvers to mut
Mutation payloads
-----------------
-``login`` and ``logout`` mutations introduced earlier in this guide work, but give very limited feedback to the client: they return either ``false`` or ``true``. Application could use additional information like an error message that could be displayed in the interface after mutation fails, or updated user state after mutation completes.
+``login`` and ``logout`` mutations introduced earlier in this guide work, but give very limited feedback to the client: they return either ``false`` or ``true``. The application could use additional information like an error message that could be displayed in the interface after mutation fails, or an updated user state after a mutation completes.
In GraphQL this is achieved by making mutations return special *payload* types containing additional information about the result, such as errors or current object state::
@@ -84,7 +84,7 @@ In GraphQL this is achieved by making mutations return special *payload* types c
}
"""
-Above mutation will return special type containing information about mutation's status, as well as either ``Error`` message or logged in ``User``. In Python this payload can be represented as simple ``dict``::
+The above mutation will return a special type containing information about the mutation's status, as well as either an ``Error`` message or a logged in ``User``. In Python this payload can be represented as a simple ``dict``::
def resolve_login(_, info, username, password):
request = info.context["request"]
@@ -94,14 +94,14 @@ Above mutation will return special type containing information about mutation's
return {"status": True, "user": user}
return {"status": False, "error": "Invalid username or password"}
-Lets take one more look at payload's fields:
+Let's take one more look at the payload's fields:
- ``status`` makes it easy for frontend logic to check if mutation succeeded or failed.
- ``error`` contains error message returned by mutation or ``null``. Errors can be simple strings, or more complex types that contain additional information for use by the client.
-``user`` field is especially noteworthy. Modern GraphQL client libraries like `Apollo CLient `_ implement automatic caching and state management, usign GraphQL types to track and automatically update stored objects data whenever new one is returned from the API.
+``user`` field is especially noteworthy. Modern GraphQL client libraries like `Apollo Client `_ implement automatic caching and state management, using GraphQL types to track and automatically update stored objects data whenever a new one is returned from the API.
-Consider mutation that changes username and its payload::
+Consider a mutation that changes username and its payload::
type Mutation {
updateUsername(id: ID!, username: String!): userMutationPayload
@@ -113,16 +113,16 @@ Consider mutation that changes username and its payload::
user: User
}
-Our client code may first perform an *optimistic update* before API executes mutation and returns response to client. This optimistic update will cause an immediate update of application interface, making it appear fast and responsive to the user. When mutation eventually completes a moment later and returns updated ``user`` one of two things will happen:
+Our client code may first perform an *optimistic update* before the API executes a mutation and returns a response to client. This optimistic update will cause an immediate update of the application interface, making it appear fast and responsive to the user. When the mutation eventually completes a moment later and returns updated ``user`` one of two things will happen:
-If mutation succeeded user doesn't see another UI update because new data returned by mutation was same as one set by optimistic update. If mutation asked for additional user fields that are dependant on username but weren't set optimistically (like link or user namechanges history), those will be updated too.
+If the mutation succeeded, the user doesn't see another UI update because the new data returned by mutation was the same as the one set by optimistic update. If mutation asked for additional user fields that are dependant on username but weren't set optimistically (like link or user name changes history), those will be updated too.
-If mutation failed changes performed by an optimistic update are overwritten by valid user state that contains pre-changed username. Client then uses ``error`` field to display error message in the interface.
+If mutation failed, changes performed by an optimistic update are overwritten by valid user state that contains pre-changed username. The client then uses the ``error`` field to display an error message in the interface.
-For above reasons it is considered a good design for mutations to return updated object whenever possible.
+For the above reasons it is considered a good design for mutations to return updated object whenever possible.
.. note::
- There is no requirement for every mutation to have its own ``Payload`` type. ``login`` and ``logout`` mutations can both define ``LoginPayload`` as return type. It is up to developer to decide how generic or specific mutation payloads will be.
+ There is no requirement for every mutation to have its own ``Payload`` type. ``login`` and ``logout`` mutations can both define ``LoginPayload`` as return type. It is up to the developer to decide how generic or specific mutation payloads will be.
Inputs
@@ -177,7 +177,7 @@ GraphQL provides a better way for solving this problem: ``input`` allows us to m
}
"""
-Now when client wants to create a new discussion, they need to provide an ``input`` object that matches the ``DiscussionInput`` definition. This input will then be validated and passed to the mutation's resolver as dict available under the ``input`` keyword argument::
+Now, when client wants to create a new discussion, they need to provide an ``input`` object that matches the ``DiscussionInput`` definition. This input will then be validated and passed to the mutation's resolver as dict available under the ``input`` keyword argument::
def resolve_create_discussion(_, info, input):
clean_input = {
@@ -198,7 +198,7 @@ Now when client wants to create a new discussion, they need to provide an ``inpu
"error: err,
}
-Another advantage of ``input``-s is that they are reusable. If we later decide to implement another mutation for updating the Discussion, we can do it like this::
+Another advantage of ``input`` types is that they are reusable. If we later decide to implement another mutation for updating the ``Discussion``, we can do it like this::
type_def = """
type Mutation {
@@ -235,7 +235,7 @@ Our ``updateDiscussion`` mutation will now accept two arguments: ``discussion``
"error: err,
}
-You may wonder why you would want to use ``input`` instead of reusing already defined type. This is because input types provide some guarantees that regular objects don't: they are serializable, and they don't implement interfaces or unions. However input fields are not limited to scalars. You can create fields that are lists, or even reference other inputs::
+You may wonder why you would want to use ``input`` instead of reusing already defined type. This is because input types provide some guarantees that regular objects don't: they are serializable, and they don't implement interfaces or unions. However, input fields are not limited to scalars. You can create fields that are lists, or even reference other inputs::
type_def = """
input PollInput {
diff --git a/docs/resolvers.rst b/docs/resolvers.rst
index b91f230a5..16508ff01 100644
--- a/docs/resolvers.rst
+++ b/docs/resolvers.rst
@@ -13,26 +13,26 @@ In Ariadne, a resolver is any Python callable that accepts two positional argume
def __call__(self, obj: Any, info: GraphQLResolveInfo, **data):
-``obj`` is a value returned by obj resolver. If resolver is *root resolver* (it belongs to the field defined on ``Query`` or ``Mutation``) and GraphQL server implementation doesn't explicitly define value for this field, the value of this argument will be ``None``.
+``obj`` is a value returned by an obj resolver. If the resolver is a *root resolver* (it belongs to the field defined on ``Query`` or ``Mutation``) and GraphQL server implementation doesn't explicitly define value for this field, the value of this argument will be ``None``.
-``info`` is the instance of ``GraphQLResolveInfo`` object specific for this field and query. It defines a special ``context`` attribute that contains any value that GraphQL server provided for resolvers on the query execution. Its type and contents are application-specific, but it is generally expected to contain application-specific data such as authentication state of the user or http request.
+``info`` is the instance of a ``GraphQLResolveInfo`` object specific for this field and query. It defines a special ``context`` attribute that contains any value that GraphQL server provided for resolvers on the query execution. Its type and contents are application-specific, but it is generally expected to contain application-specific data such as authentication state of the user or http request.
.. note::
- ``context`` is just one of many attributes that can be found on ``GraphQLResolveInfo``, but it is by far the most commonly used one. Other attributes enable developers to introspect the query that is currently executed and implement new utilities and abstractions, but documenting that is out of Ariadne's scope. Still, if you are interested, you can find the list of all attributes `here `_.
+ ``context`` is just one of many attributes that can be found on ``GraphQLResolveInfo``, but it is by far the most commonly used one. Other attributes enable developers to introspect the query that is currently executed and implement new utilities and abstractions, but documenting that is out of Ariadne's scope. If you are interested, you can find the list of all attributes `here `_.
Resolver maps
-------------
-Resolver needs to be bound to valid type's field in the schema in order to be used during the query execution.
+A resolver needs to be bound to a valid type's field in the schema in order to be used during the query execution.
-To bind resolvers to schema Ariadne uses special ``ResolverMap`` object that is initialized with single argument - name of the type::
+To bind resolvers to schema, Ariadne uses a special ``ResolverMap`` object that is initialized with single argument - name of the type::
from ariadne import ResolverMap
query = ResolverMap("Query")
-Above ``ResolverMap`` instance knows that it maps its resolvers to ``Query`` type, and enables you to assign resolver functions to this type fields. This can be done using the ``field`` method implemented by resolver map::
+The above ``ResolverMap`` instance knows that it maps its resolvers to ``Query`` type, and enables you to assign resolver functions to these type fields. This can be done using the ``field`` method implemented by the resolver map::
from ariadne import ResolverMap
@@ -48,7 +48,7 @@ Above ``ResolverMap`` instance knows that it maps its resolvers to ``Query`` typ
def resolve_hello(*_):
return "Hello!"
-``@query.field`` decorator is non-wrapping - it simply registers given function as resolver for specified field and then returns it as it is. This makes it easy to test or reuse resolver functions between different types or even APIs::
+``@query.field`` decorator is non-wrapping - it simply registers a given function as a resolver for specified field and then returns it as it is. This makes it easy to test or reuse resolver functions between different types or even APIs::
user = ResolverMap("User")
client = ResolverMap("Client")
@@ -71,7 +71,7 @@ Alternatively, ``query.field`` can also be called as regular method::
Handling arguments
------------------
-If GraphQL field specifies any arguments, those arguments values will be passed to the resolver as keyword arguments::
+If GraphQL field specifies any arguments, those argument values will be passed to the resolver as keyword arguments::
type_def = """
type Query {
@@ -87,7 +87,7 @@ If GraphQL field specifies any arguments, those arguments values will be passed
Calendar.get_holidays_in_year(year)
return Calendar.get_all_holidays()
-If field argument is marked as required (by following type with ``!``, eg. ``year: Int!``), you can skip the ``=None`` in your kwarg::
+If a field argument is marked as required (by following type with ``!``, eg. ``year: Int!``), you can skip the ``=None`` in your ``kwarg``::
@query.field("holidays")
def resolve_holidays(*_, year):
@@ -99,7 +99,7 @@ If field argument is marked as required (by following type with ``!``, eg. ``yea
Aliases
-------
-You can use ``ResolverMap.alias`` to quickly make field an alias for differently named attribute on resolved object::
+You can use ``ResolverMap.alias`` to quickly make a field an alias for a differently-named attribute on a resolved object::
type_def = """
type User {
@@ -114,7 +114,7 @@ You can use ``ResolverMap.alias`` to quickly make field an alias for differently
Fallback resolvers
------------------
-Schema can potentially define many types and fields, and defining resolver or alias for every single one of them can become large burden.
+Schema can potentially define numerous types and fields, and defining a resolver or alias for every single one of them can become a large burden.
Ariadne provides two special "fallback resolvers" that scan schema during initialization, and bind default resolvers to fields that don't have any resolver set::
@@ -124,9 +124,9 @@ Ariadne provides two special "fallback resolvers" that scan schema during initia
start_simple_server(type_defs, resolvers + [fallback_resolvers])
-Above example starts simple GraphQL API using types and resolvers imported from other modules, but it also adds ``fallback_resolvers`` to list of resolvers that should be used in creation of schema.
+The above example starts a simple GraphQL API using types and resolvers imported from other modules, but it also adds ``fallback_resolvers`` to the list of resolvers that should be used in creation of schema.
-``fallback_resolvers`` perform any case conversion and simply seek attribute named in same way as field they are bound to using "default resolver" strategy described in next chapter.
+``fallback_resolvers`` perform any case conversion and simply seek the attribute named in the same way as the field they are bound to using "default resolver" strategy described in the next chapter.
If your schema uses JavaScript convention for naming its fields (as do all schema definitions in this guide) you may want to instead use the ``snake_case_fallback_resolvers`` that converts field name to Python's ``snake_case`` before looking it up on the object::
@@ -140,11 +140,11 @@ If your schema uses JavaScript convention for naming its fields (as do all schem
Default resolver
----------------
-Both ``ResolverMap.alias`` and fallback resolvers use Ariadne-provided default resolver to implement its functionality.
+Both ``ResolverMap.alias`` and fallback resolvers use an Ariadne-provided default resolver to implement its functionality.
-This resolver takes target attribute name and (depending if ``obj`` is ``dict`` or not) uses either ``obj.get(attr_name)`` or ``getattr(obj, attr_name, None)`` to resolve the value that should be returned.
+This resolver takes a target attribute name and (depending if ``obj`` is ``dict`` or not) uses either ``obj.get(attr_name)`` or ``getattr(obj, attr_name, None)`` to resolve the value that should be returned.
-In below example both representations of ``User`` type are supported by the default resolver::
+In the below example, both representations of ``User`` type are supported by the default resolver::
type_def = """
type User {
@@ -171,11 +171,11 @@ In below example both representations of ``User`` type are supported by the defa
Understanding schema binding
----------------------------
-When Ariadne initializes GraphQL server, it iterates over list of objects passed to ``resolvers`` argument and calls ``bind_to_schema`` method of each item with single argument: instance of ``GraphQLSchema`` object representing parsed schema used by the server.
+When Ariadne initializes GraphQL server, it iterates over a list of objects passed to a ``resolvers`` argument and calls ``bind_to_schema`` method of each item with a single argument: instance of ``GraphQLSchema`` object representing parsed schema used by the server.
-``ResolverMap`` and fallback resolvers introduced above don't access the schema until their ``bind_to_schema`` method is called. It is safe to create, call methods as well as perform other state mutations on those objects util they are passed to Ariadne.
+``ResolverMap`` and the fallback resolvers introduced above don't access the schema until their ``bind_to_schema`` method is called. It is safe to create, call methods and perform other state mutations on those objects until they are passed to Ariadne.
-You can easily implement custom utility class that can be used in Ariadne::
+You can easily implement a custom utility class that can be used in Ariadne::
from graphql.type import GraphQLSchema
@@ -183,4 +183,4 @@ You can easily implement custom utility class that can be used in Ariadne::
def bind_to_schema(self, schema: GraphQLSchema) -> None:
pass # insert custom logic here
-In later parts of documentation other special types will be introduced, that internally use ``bind_to_schema`` to implement their logic.
+In later parts of the documentation, other special types will be introduced that internally use ``bind_to_schema`` to implement their logic.
diff --git a/docs/scalars.rst b/docs/scalars.rst
index efc4c5674..52e36da15 100644
--- a/docs/scalars.rst
+++ b/docs/scalars.rst
@@ -1,7 +1,7 @@
Custom scalars
==============
-Custom scalars allow you to convert your Python objects to JSON-serializable form in query results, as well as convert those JSON forms back to Python objects back when they are passed as arguments or ``input`` values.
+Custom scalars allow you to convert your Python objects to a JSON-serializable form in query results, as well as convert those JSON forms back to Python objects when they are passed as arguments or ``input`` values.
Example read-only scalar
@@ -16,20 +16,20 @@ Consider this API defining ``Story`` type with ``publishedOn`` field::
}
"""
-The ``publishedOn`` field resolver returns instance of type ``datetime``, but in API this field is defined as ``String``. This means that our datetime will be passed throught the ``str()`` before being returned to client::
+The ``publishedOn`` field resolver returns an instance of type ``datetime``, but in the API this field is defined as ``String``. This means that our datetime will be passed through the ``str()`` before being returned to client::
{
"publishedOn": "2018-10-26 17:28:54.416434"
}
-This may look acceptable, but there are better formats to serialize timestamps for later deserialization on the client, like ISO 8601. This conversion could be performed in dedicated resolver::
+This may look acceptable, but there are better formats to serialize timestamps for later deserialization on the client, like ISO 8601. This conversion could be performed in a dedicated resolver::
def resolve_published_on(obj, *_):
return obj.published_on.isoformat()
-...but now the developer has to remember to define custom resolver for every field that returns ``datetime``. This really adds up the boilerplate to the API, and makes it harder to use abstractions auto-generating the resolvers for you.
+However, the developer now has to remember to define a custom resolver for every field that returns ``datetime``. This really adds a boilerplate to the API, and makes it harder to use abstractions auto-generating the resolvers for you.
-Instead, GraphQL API can be told how to serialize dates by defining custom scalar type::
+Instead, GraphQL API can be told how to serialize dates by defining the custom scalar type::
type_defs = """
type Story {
@@ -40,15 +40,15 @@ Instead, GraphQL API can be told how to serialize dates by defining custom scala
scalar Datetime
"""
-If you will try to query this field now, you will get an error::
+If you try to query this field now, you will get an error::
{
"error": "Unexpected token A in JSON at position 0"
}
-This is because custom scalar has been defined, but it's currently missing logic for serializing Python values to JSON form and ``Datetime`` instances are not JSON serializable by default.
+This is because a custom scalar has been defined, but it's currently missing logic for serializing Python values to JSON form and ``Datetime`` instances are not JSON serializable by default.
-We need to add special serializing resolver to our ``Datetime`` scalar that will implement the logic we are expecting. Ariadne provides ``Scalar`` class that enables just that::
+We need to add a special serializing resolver to our ``Datetime`` scalar that will implement the logic we are expecting. Ariadne provides ``Scalar`` class that enables just that::
from ariadne import Scalar
@@ -58,19 +58,19 @@ We need to add special serializing resolver to our ``Datetime`` scalar that will
def serialize_datetime(value):
return value.isoformat()
-Include the ``datetime_scalar`` in the list of ``resolvers`` passed to your GraphQL server. Custom serialization logic will now be used when resolver for ``Datetime`` field returns value other than ``None``::
+Include the ``datetime_scalar`` in the list of ``resolvers`` passed to your GraphQL server. Custom serialization logic will now be used when a resolver for the ``Datetime`` field returns a value other than ``None``::
{
"publishedOn": "2018-10-26T17:45:08.805278"
}
-Now we can reuse our custom scalar across the API to serialize ``datetime`` instances in standardized format that our clients will understand.
+We can now reuse our custom scalar across the API to serialize ``datetime`` instances in a standardized format that our clients will understand.
Scalars as input
----------------
-What will happen if now we create field or mutation that defines argument of the type ``Datetime``? We can find out using basic resolver::
+What will happen if now we create a field or mutation that defines an argument of the type ``Datetime``? We can find out using a basic resolver::
type_defs = """
type Query {
@@ -81,12 +81,12 @@ What will happen if now we create field or mutation that defines argument of the
def resolve_stories(*_, **data):
print(data.get("publishedOn")) # what value will "publishedOn" be?
-``data.get("publishedOn")`` will print whatever value was passed to the argument, coerced to respective Python type. For some scalars this may do the trick, but for this one it's expected that input gets converted back to the ``datetime`` instance.
+``data.get("publishedOn")`` will print whatever value was passed to the argument, coerced to the respective Python type. For some scalars this may do the trick, but for this one it's expected that input gets converted back to the ``datetime`` instance.
-To turn our *read-only* scalar into *bidirectional* scalar, we will need to add two functions to ``Scalar`` that was created in previous step:
+To turn our *read-only* scalar into *bidirectional* scalar, we will need to add two functions to the ``Scalar`` that was created in the previous step:
-- ``value_parser(value)`` that will be used when scalar value is passed as part of query ``variables``.
-- ``literal_parser(ast)`` that will be used when scalar value is passed as part of query content (eg. ``{ stories(publishedOn: "2018-10-26T17:45:08.805278") { ... } }``).
+- ``value_parser(value)`` that will be used when the scalar value is passed as part of query ``variables``.
+- ``literal_parser(ast)`` that will be used when the scalar value is passed as part of query content (e.g. ``{ stories(publishedOn: "2018-10-26T17:45:08.805278") { ... } }``).
Those functions can be implemented as such::
@@ -101,13 +101,13 @@ Those functions can be implemented as such::
value = str(ast.value)
return parse_datetime_value(value) # reuse logic from parse_value
-There are few things happening in the above code, so let's go through it step by step:
+There are a few things happening in the above code, so let's go through it step by step:
-If value is passed as part of query's ``variables``, it's passed to ``parse_datetime_value``.
+If the value is passed as part of query's ``variables``, it's passed to ``parse_datetime_value``.
-If value is not empty, ``dateutil.parser.parse`` is used to parses it to the valid Python ``datetime`` object instance that is then returned.
+If the value is not empty, ``dateutil.parser.parse`` is used to parse it to the valid Python ``datetime`` object instance that is then returned.
-If value is incorrect and either ``ValueError`` or ``TypeError`` exception is raised by the ``dateutil.parser.parse`` GraphQL server interprets this as sign that entered value is incorrect because it can't be transformed to internal representation and returns automatically generated error message to the client that consists of two parts:
+If value is incorrect and either a ``ValueError`` or ``TypeError`` exception is raised by the ``dateutil.parser.parse`` GraphQL server interprets this as a sign that the entered value is incorrect because it can't be transformed to internal representation and returns an automatically generated error message to the client that consists of two parts:
- Part supplied by GraphQL, for example: ``Expected type Datetime!, found "invalid string"``
- Exception message: ``time data 'invalid string' does not match format '%Y-%m-%d'``
@@ -120,8 +120,8 @@ Complete error message returned by the API will look like this::
You can raise either ``ValueError`` or ``TypeError`` in your parsers.
.. warning::
- Because error message returned by the GraphQL includes original exception message from your Python code, it may contain details specific to your system or implementation that you may not want to make known to the API consumers. You may decide to catch the original exception with ``except (ValueError, TypeError)`` and then raise your own ``ValueError`` with custom message or no message at all to prevent this from happening.
+ Because the error message returned by the GraphQL includes the original exception message from your Python code, it may contain details specific to your system or implementation that you may not want to make known to the API consumers. You may decide to catch the original exception with ``except (ValueError, TypeError)`` and then raise your own ``ValueError`` with a custom message or no message at all to prevent this from happening.
-If value is specified as part of query content, it's ``ast`` node is instead passed to ``parse_datetime_literal`` to give Scalar a chance to introspect type of the node (implementations for those be found `here `_).
+If a value is specified as part of query content, its ``ast`` node is instead passed to ``parse_datetime_literal`` to give Scalar a chance to introspect type of the node (implementations for those be found `here `_).
-Logic implemented in the ``parse_datetime_literal`` may be completely different from one in the ``parse_datetime_value``, however, in this example ``ast`` node is simply unpacked, coerced to ``str`` and then passed to ``parse_datetime_value``, reusing the parsing logic from that other function.
\ No newline at end of file
+Logic implemented in the ``parse_datetime_literal`` may be completely different from that in the ``parse_datetime_value``, however, in this example ``ast`` node is simply unpacked, coerced to ``str`` and then passed to ``parse_datetime_value``, reusing the parsing logic from that other function.
\ No newline at end of file
diff --git a/docs/wsgi-middleware.rst b/docs/wsgi-middleware.rst
index feac6ead1..426b19612 100644
--- a/docs/wsgi-middleware.rst
+++ b/docs/wsgi-middleware.rst
@@ -3,18 +3,18 @@ WSGI Middleware
.. module:: ariadne
-Ariadne provides :py:class:`GraphQLMiddleware` that realizes following goals:
+Ariadne provides :py:class:`GraphQLMiddleware` that realizes the following goals:
- is production-ready WSGI middleware that can be added to existing setups to start building GraphQL API quickly.
- it's designed to encourage easy customization through extension.
- provides reference implementation for Ariadne GraphQL server.
-- implements `make_simple_server` utility for running local development servers without having to setup full-fledged web framework.
+- implements `make_simple_server` utility for running local development servers without having to set up a full-fledged web framework.
Using as Middleware
-------------------
-To add GraphQL API to your project using ``GraphQLMiddleware`` instantiate it with your existing WSGI application as first argument, type defs as second and resolvers as third::
+To add GraphQL API to your project using ``GraphQLMiddleware``, instantiate it with your existing WSGI application as a first argument, type defs as second and resolvers as third::
# in wsgi.py
import os
@@ -28,7 +28,7 @@ To add GraphQL API to your project using ``GraphQLMiddleware`` instantiate it wi
django_application = get_wsgi_application()
application = GraphQLMiddleware(django_application, type_defs, resolvers)
-Now direct your WSGI container to `wsgi.application`. GraphQL API is available on ``/graphql/`` by default, but this can be customized by passing path as fourth argument::
+Now direct your WSGI container to `wsgi.application`. GraphQL API is available on ``/graphql/`` by default, but this can be customized by passing path as a fourth argument::
# GraphQL will now be available on "/graphql-v2/" path
application = GraphQLMiddleware(
@@ -53,7 +53,7 @@ Customizing context or root
:param request_data: json that was sent as request body and deserialized to `dict`.
:return: value that should be passed to resolvers as ``context`` attribute on ``info`` argument.
-Following example shows custom GraphQL middleware that defines its own root and context::
+The following example shows custom GraphQL middleware that defines its own root and context::
from ariadne import GraphQLMiddleware: