Metadata-Version: 2.1
Name: tartiflette-starlette
Version: 0.6.0
Summary: ASGI support for the Tartiflette Python GraphQL engine
Home-page: https://github.com/tartiflette/tartiflette-starlette
Author: Florimond Manca
Author-email: florimond.manca@gmail.com
License: MIT
Description: <div align="center">
          <img src="https://user-images.githubusercontent.com/158689/58954519-b05ad680-8799-11e9-9134-90622e7731f3.png" alt="tartiflette-starlette logo"/>
        </div>
        
        <p align="center">
          <a href="https://travis-ci.org/tartiflette/tartiflette-starlette">
            <img src="https://travis-ci.org/tartiflette/tartiflette-starlette.svg?branch=master" alt="Build status">
          </a>
          <a href="https://pypi.org/project/tartiflette-starlette">
            <img src="https://badge.fury.io/py/tartiflette-starlette.svg" alt="Package version">
          </a>
          <a href="https://github.com/ambv/black">
            <img src="https://img.shields.io/badge/code_style-black-000000.svg" alt="Code style">
            </a>
        </p>
        
        `tartiflette-starlette` is a wrapper that provides ASGI support for the [Tartiflette] Python GraphQL engine.
        
        [tartiflette]: https://tartiflette.io
        
        Build your GraphQL API with Tartiflette, then use the included `TartifletteApp` and get the following:
        
        - Compatibility with any ASGI server and framework.
        - Standalone and sub-app serving.
        - Built-in [GraphiQL] client.
        - Support for [GraphQL subscriptions over WebSocket](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md).
        
        [graphiql]: https://github.com/graphql/graphiql
        
        ---
        
        **Note**: `tartiflette-starlette >= 0.6` is only compatible with Tartiflette 1.x. For compatibility with Tartiflette 0.x, please install `tartiflette-starlette == 0.5.2`.
        
        ---
        
        **Table of contents**
        
        - [Quickstart](#quickstart)
        - [Installation](#installation)
        - [User guide](#user-guide)
          - [Standalone serving](#standalone-serving)
          - [ASGI submounting](#asgi-submounting)
          - [Making requests](#making-requests)
          - [Accessing request information](#accessing-request-information)
          - [GraphiQL client](#graphiql-client)
          - [WebSocket subscriptions (Advanced)](#websocket-subscriptions-advanced)
        - [API Reference](#api-reference)
        - [FAQ](#faq)
        
        ## Quickstart
        
        ```python
        from tartiflette import Resolver
        from tartiflette_starlette import TartifletteApp
        
        @Resolver("Query.hello")
        async def hello(parent, args, context, info):
            name = args["name"]
            return f"Hello, {name}!"
        
        sdl = """
          type Query {
            hello(name: String): String
          }
        """
        
        app = TartifletteApp(sdl=sdl)
        ```
        
        Save the file as `graphql.py` and start a [uvicorn] server:
        
        [uvicorn]: https://www.uvicorn.org
        
        ```bash
        uvicorn graphql:app
        ```
        
        > **Note**: the GraphQL endpoint is exposed on `/` by default.
        
        Make a request:
        
        ```bash
        curl -H "Content-Type: application/graphql"  -d '{ hello(name: "Chuck") }' http://localhost:8000
        ```
        
        Response:
        
        ```json
        { "data": { "hello": "Hello, Chuck!" } }
        ```
        
        Or access `http://localhost:8000` in a browser to make interactive queries using the built-in [GraphiQL] client:
        
        ![](https://github.com/tartiflette/tartiflette-starlette/raw/master/img/graphiql.png)
        
        ## Installation
        
        1. Install Tartiflette's external dependencies as explained in the [Tartiflette tutorial](https://tartiflette.io/docs/tutorial/install-tartiflette).
        2. Install `tartiflette-starlette` from PyPI:
        
        ```bash
        pip install "tartiflette-starlette==0.*"
        ```
        
        This will also install [Tartiflette] and [Starlette], so you're good to go!
        
        [starlette]: https://www.starlette.io
        
        **Note**: `tartiflette-starlette` requires Python 3.6+.
        
        ## User guide
        
        The [`TartifletteApp`](#tartifletteapp) class is an ASGI3-compliant application. There are two ways to use it:
        
        - Serve it as a standalone ASGI app.
        - Mount it as an endpoint of another ASGI app (e.g. a Starlette application).
        
        ### Standalone serving
        
        The [Quickstart](#quickstart) example shows how to build a `TartifletteApp` and serve it as a standalone ASGI app.
        
        The app is served using Uvicorn, but any other ASGI web server will do, for example:
        
        - [uvicorn]
        - [hypercorn](https://github.com/pgjones/hypercorn)
        - [daphne](https://github.com/django/daphne)
        
        ### ASGI submounting
        
        Most ASGI web frameworks provide a way to **mount** another ASGI app at a given URL prefix. You can use this to serve a `TartifletteApp` at an endpoint such as `/graphql` on the root ASGI application.
        
        This is useful to have **a GraphQL endpoint _and_ other (non-GraphQL) endpoints** within a single application. For example, to have a REST endpoint at `/api/users` and a GraphQL endpoint at `/graphql`.
        
        > **Important**: this should work with _**any**_ web framework that supports ASGI submounting — it doesn't have to be Starlette. See also: [What is the role of Starlette?](#what-is-the-role-of-starlette)
        
        #### Starlette example
        
        ```python
        from starlette.applications import Starlette
        from starlette.responses import PlainTextResponse
        from tartiflette import Resolver
        from tartiflette_starlette import TartifletteApp, mount
        
        app = Starlette()
        
        @app.route("/")
        async def home(request):
          return PlainTextResponse("Hello, world!")
        
        @Resolver("Query.hello")
        async def hello(parent, args, context, info):
            name = args["name"]
            return f"Hello, {name}!"
        
        sdl = """
          type Query {
            hello(name: String): String
          }
        """
        
        graphql = TartifletteApp(sdl=sdl)
        mount.starlette(app, "/graphql", graphql)  # (*)
        ```
        
        > (\*) This is a shorthand for:
        >
        > ```python
        > app.mount("/graphql", graphql)
        > app.add_event_handler("startup", graphql.startup)
        > ```
        
        Save the file as `app.py`, and serve it with [uvicorn]:
        
        ```bash
        uvicorn app:app
        ```
        
        Make a request:
        
        ```bash
        curl -H "Content-Type: application/graphql/"  -d '{ hello(name: "Chuck") }' http://localhost:8000
        ```
        
        > **Note**: if you receive a `307 Temporary Redirect` response, make sure to include the trailing slash: `/graphql/`.
        
        Response:
        
        ```json
        { "data": { "hello": "Hello, Chuck!" } }
        ```
        
        #### General approach
        
        Assuming you have an instance of `TartifletteApp` called `graphql`, you need to:
        
        1. Add the `graphql` app as a sub-application (also known as "mounting"). The parent ASGI application may expose a method such as `.mount()` for this purpose.
        2. Add `graphql.startup` as a startup event handler so that the Tartiflette engine is built upon application startup. Note that:
        
        - Not doing this will result in a `RuntimeError` when requesting the GraphQL endpoint.
        - The parent ASGI application may expose a method such as `.add_event_handler()` for this purpose.
        - This is only required if the parent ASGI application does not call lifespan event handlers for sub-applications, as is the case for Starlette.
        
        **Tip**: the [`mount`](#mount) module provides mounting helpers for various ASGI frameworks.
        
        ### Making requests
        
        `tartiflette-starlette` complies with the [GraphQL spec](https://graphql.org/learn/serving-over-http/#http-methods-headers-and-body), which allows you to pass the query in several ways:
        
        - **URL query string** (methods: `GET`, `POST`):
        
        ```bash
        curl 'http://localhost:8000?query=\{hello(name:"Chuck")\}'
        ```
        
        - **JSON-encoded body** (methods: `POST`):
        
        ```bash
        curl \
          -H "Content-Type: application/json" \
          -d '{"query": "{ hello(name: \"Chuck\") }"}' \
          http://localhost:8000
        ```
        
        - **Raw body** with the `application/graphql` content type (methods: `POST`):
        
        ```bash
        curl \
          -H "Content-Type: application/graphql" \
          -d '{ hello(name: "Chuck") }' \
          http://localhost:8000
        ```
        
        **Note**: you may have your GraphQL API served at a different endpoint.
        
        ### Accessing request information
        
        You can access the Starlette `Request` object from resolvers using `context["req"]`:
        
        ```python
        @Resolver("Query.whoami")
        async def resolve_whoami(parent, args, context, info) -> str:
            request = context["req"]
            return getattr(request.state, "user", "a mystery")
        ```
        
        See also [Requests](https://www.starlette.io/requests/) in the Starlette documentation.
        
        ### GraphiQL client
        
        By default, the GraphQL endpoint provided by `TartifletteApp` serves a [GraphiQL] client when it is accessed from a web browser. It can be customized using the `GraphiQL` helper.
        
        Here's an example:
        
        ```python
        from tartiflette_starlette import TartifletteApp, GraphiQL
        
        app = TartifletteApp(
            sdl="""
            type Query {
                hello(name: String): String
            }
            """,
            graphiql=GraphiQL(
                path="/graphiql",
                default_headers={"Authorization": "Bearer 123"},
                default_variables={"name": "world"},
                default_query="""
                query Hello($name: String) {
                    hello(name: $name)
                }
                """,
            ),
        )
        ```
        
        Save this as `graphql.py` and run `uvicorn graphql:app`. You should see the customized GraphiQL client when accessing http://127.0.0.1/graphiql:
        
        ![](https://github.com/tartiflette/tartiflette-starlette/raw/master/img/graphiql-custom.png)
        
        See [`GraphiQL`](#graphiql) in the API reference for a complete description of the available options.
        
        ### Providing additional context to resolvers
        
        You can inject your own services, functions or data into the GraphQL `context` using the `context` option.
        
        For example, assuming you use a publish/subscribe library named `pubsub`, you could write:
        
        ```python
        from pubsub import PubSub  # Fake
        
        @Resolver("Query.human")
        async def resolve_human(parent, args, context, info):
            pubsub = context["pubsub"]
            # ...
            await pubsub.publish("human_fetched", args)
        
        graphql = TartifletteApp(
          # ...,
          context={"pubsub": PubSub()},
        )
        ```
        
        ### WebSocket subscriptions (Advanced)
        
        This package provides support for [GraphQL subscriptions](https://graphql.org/blog/subscriptions-in-graphql-and-relay/) over WebSocket. Subscription queries can be issued via the built-in GraphiQL client, as well as [Apollo GraphQL](https://www.apollographql.com/docs/react/advanced/subscriptions/) and any other client that uses the [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) protocol.
        
        Example:
        
        ```python
        import asyncio
        from tartiflette import Subscription
        from tartiflette_starlette import TartifletteApp, GraphiQL
        
        sdl = """
        type Query {
          _: Boolean
        }
        
        type Subscription {
          timer(seconds: Int!): Timer
        }
        
        enum Status {
          RUNNING
          DONE
        }
        
        type Timer {
          remainingTime: Int!
          status: Status!
        }
        """
        
        @Subscription("Subscription.timer")
        async def on_timer(parent, args, context, info):
            seconds = args["seconds"]
            for i in range(seconds):
                yield {"timer": {"remainingTime": seconds - i, "status": "RUNNING"}}
                await asyncio.sleep(1)
            yield {"timer": {"remainingTime": 0, "status": "DONE"}}
        
        app = TartifletteApp(
            sdl=sdl,
            subscriptions=True,
            graphiql=GraphiQL(
                default_query="""
                subscription {
                  timer(seconds: 5) {
                    remainingTime
                    status
                  }
                }
                """
            ),
        )
        ```
        
        > **Note**: the subscriptions endpoint is exposed on `/subscriptions` by default.
        
        Save this file as `graphql.py`, then run `$ uvicorn graphql:app`. Open the GraphiQL client at http://localhost:8000, and hit "Play"! The timer should update on real-time.
        
        ![](https://github.com/tartiflette/tartiflette-starlette/raw/master/img/graphiql-subscriptions.png)
        
        See [`Subscriptions`](#subscriptions) in the API reference for a complete description of the available options.
        
        For more information on using subscriptions in Tartiflette, see the [Tartiflette documentation](https://tartiflette.io/docs/api/subscription).
        
        ## API Reference
        
        > **Note**: unless specified, components documented here can be imported from `tartiflette_starlette` directly, e.g. `from tartiflette_starlette import TartifletteApp`.
        
        ### `TartifletteApp`
        
        #### Parameters
        
        **Note**: all parameters are keyword-only.
        
        - `engine` (`Engine`): a Tartiflette [engine](https://tartiflette.io/docs/api/engine). Required if `sdl` is not given.
        - `sdl` (`str`): a GraphQL schema defined using the [GraphQL Schema Definition Language](https://graphql.org/learn/schema/). Required if `engine` is not given.
        - `path` (`str`, optional): the path which clients should make GraphQL queries to. Defaults to `"/"`.
        - `graphiql` (`GraphiQL` or `bool`, optional): configuration for the GraphiQL client. Defaults to `True`, which is equivalent to `GraphiQL()`. Use `False` to not register the GraphiQL client.
        - `subscriptions` (`Subscriptions` or `bool`, optional): subscriptions configuration. Defaults to `True`, which is equivalent to `Subscriptions(path="/subscriptions")`. Leave empty or pass `None` to not register the subscription WebSocket endpoint.
        - `context` (`dict`, optional): a copy of this dictionary is passed to resolvers when executing a query. Defaults to `{}`. Note: the Starlette `Request` object is always present as `req`.
        - `schema_name` (`str`, optional): name of the GraphQL schema from the [Schema Registry](https://tartiflette.io/docs/api/schema-registry/) which should be used — mostly for advanced usage. Defaults to `"default"`.
        
        #### Methods
        
        - `__call__(scope, receive, send)`: ASGI3 implementation.
        
        #### Error responses
        
        | Status code                | Description                                                                                                                      |
        | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
        | 400 Bad Request            | The GraphQL query could not be found in the request data.                                                                        |
        | 404 Not Found              | The request does not match the GraphQL or GraphiQL endpoint paths.                                                               |
        | 405 Method Not Allowed     | The HTTP method is not one of `GET`, `HEAD` or `POST`.                                                                           |
        | 415 Unsupported Media Type | The POST request made to the GraphQL endpoint uses a `Content-Type` different from `application/json` and `application/graphql`. |
        
        ### `GraphiQL`
        
        Configuration helper for the GraphiQL client.
        
        #### Parameters
        
        **Note**: all parameters are keyword-only.
        
        - `path` (`str`, optional): the path of the GraphiQL endpoint, **relative to the root path which `TartifletteApp` is served at**. If not given, defaults to the `path` given to `TartifletteApp`.
        - `default_headers` (`dict`, optional): extra HTTP headers to send when calling the GraphQL endpoint.
        - `default_query` (`str`, optional): the default query to display when accessing the GraphiQL interface.
        - `default_variables` (`dict`, optional): default [variables][graphql-variables] to display when accessing the GraphiQL interface.
        - `template` (`str`, optional): an HTML template to use instead of the default one. In the template, `default_headers`, `default_query` and `default_variables`, as well as the GraphQL `endpoint`, are available as strings (JSON-encoded if needed) using template string substitutions, e.g.:
        
        ```js
        const endpoint = `${endpoint}`; // This is where the API call should be made.
        const defaultHeaders = JSON.parse(`${default_headers}`);
        ```
        
        [graphql-variables]: https://graphql.org/learn/queries/#variables
        
        ### `Subscriptions`
        
        Configuration helper for WebSocket subscriptions.
        
        #### Parameters
        
        **Note**: all parameters are keyword-only.
        
        - `path` (`str`): the path of the subscriptions WebSocket endpoint, **relative to the root path which `TartifletteApp` is served at**. If not given, defaults to `/subscriptions`.
        
        ### `mount`
        
        This module contains helpers for mounting a `TartifletteApp` on other ASGI applications. Use these helpers to make sure you comply with the steps described in [General approach](#general-approach).
        
        #### Parameters
        
        All mounting helpers expect the same parameters:
        
        - `parent` (ASGI app): the parent ASGI application which the `TartifletteApp` must be mounted onto.
        - `path` (`str`): the URL path where the `TartifletteApp` should be mounted.
        - `app` (`TartifletteApp`): the `TartifletteApp` to mount.
        - `**kwargs` (any): extra keyword arguments passed to the mount implementation of the `parent` app.
        
        #### Available helpers
        
        | Helper              | Mount implementation | Startup event handler implementation |
        | ------------------- | -------------------- | ------------------------------------ |
        | `mount.starlette()` | `parent.mount()`     | `parent.add_event_handler()`         |
        
        > Missing a helper for your favorite framework? Feel free to [open a pull request](https://github.com/tartiflette/tartiflette-starlette/compare)!
        
        ## FAQ
        
        ### Does this package ship with Tartiflette?
        
        **Yes**. Everything is included, which allows you to start building your GraphQL API right away. See also [Installation](#installation).
        
        ### Do I need to learn GraphQL/Tartiflette to use this package?
        
        **Yes**: once you've got the `TartifletteApp` ASGI app up and running, you're in Tartiflette territory.
        
        Here are some resources to get you started:
        
        - [Tartiflette tutorial](https://tartiflette.io/docs/tutorial/getting-started)
        - [Introduction to GraphQL](https://graphql.org/learn/)
        - [Tartiflette API reference](https://tartiflette.io/docs/api/engine)
        
        ### What is the role of Starlette?
        
        `tartiflette-starlette` uses Starlette as a lightweight ASGI toolkit: internally, it uses Starlette's request and response classes, and some other components.
        
        Luckily, this does not require your applications to use Starlette at all.
        
        For example, if you are [submounting your GraphQL app](#submounting-on-another-asgi-app) on an app built with an async web framework, this framework does not need to use Starlette — it just needs to speak ASGI.
        
        ### What is ASGI?
        
        ASGI provides a standard interface between async-capable Python web servers, frameworks, and applications.
        
        See also the [ASGI documentation](https://asgi.readthedocs.io/en/latest/).
        
        ## Contributing
        
        Want to contribute? Awesome! Be sure to read our [Contributing guidelines](https://github.com/tartiflette/tartiflette-starlette/tree/master/CONTRIBUTING.md).
        
        ## Changelog
        
        Changes to this project are recorded in the [changelog](https://github.com/tartiflette/tartiflette-starlette/tree/master/CHANGELOG.md).
        
        ## License
        
        MIT
        
        
        # Changelog
        
        All notable changes to this project will be documented in this file.
        
        The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
        and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
        
        ## Unreleased
        
        ## 0.6.0 - 2019-10-18
        
        ### Added
        
        - Add support for Tartiflette 1.x. (Pull #58)
        - Officialize support for Python 3.8. (Pull #80)
        
        ### Removed
        
        - Drop support for Tartiflette 0.x. (Pull #58)
        
        ## 0.5.2 - 2019-10-09
        
        ### Added
        
        - Add support for Python 3.8. (Pull #55)
        
        ### Fixed
        
        - Type annotations are now correctly detected by `mypy`. (Pull #66)
        - Fix a bug that prevented the GraphiQL web interface from making queries when the application was mounted on a parent ASGI app. (Pull #51)
        
        ## 0.5.1 - 2019-07-16
        
        ### Fixed
        
        - Fixed a bug that prevented accessing the GraphiQL interface when subscriptions were not enabled.
        
        ## 0.5.0 - 2019-07-12
        
        ### Added
        
        - WebSocket subscriptions, configurable with the new `subscriptions` option on `TartifletteApp`.
        - Pass extra context to resolvers using the new `context` option on `TartifletteApp`.
        
        ## 0.4.0 - 2019-07-04
        
        ### Added
        
        - Support for Tartiflette 0.12.x.
        - Add a `mount` module with submounting helpers.
        - Add `mount.starlette()`.
        
        ### Changed
        
        - Due to the new [engine cooking API](https://tartiflette.io/docs/api/engine#cook-your-tartiflette) in Tartiflette 0.12, `TartifletteApp` now includes a startup event handler responsible for building the GraphQL engine. If submounting, it **must** be registered on the parent ASGI app. Helpers in the `mount` module take care of this for you.
        
        ### Removed
        
        - Drop support for Tartiflette 0.11.x and below.
        
        ## 0.3.0 - 2019-07-03
        
        ### Added
        
        - GraphiQL configuration via the `GraphiQL` helper. Options: `path`, `default_query`, `default_headers`, `default_variables`, `template`.
        
        ### Changed
        
        - Internal refactoring that leverages more of Starlette's capabilities.
        - Documentation improvements.
        
        ## 0.2.0 - 2019-06-10
        
        ### Added
        
        - Support for `starlette>=0.12` (previously `>=0.12.0b3`).
        - Tartiflette is now installed too when installing `tartiflette-starlette`.
        
        ### Changed
        
        - The default `path` is now `""` (previously `"/"`).
        - The request is now accessible in the GraphQL context via `context["req"]` (previously `context["request"]`).
        - If no error occurred, the `errors` field is not present in the response anymore (previously was `None`).
        
        ### Fixed
        
        - More robust URL matching on `TartifletteApp`.
        
        ## 0.1.1 - 2019-04-28
        
        ### Fixed
        
        - Add missing `graphiql.html` package asset.
        
        ## 0.1.0 - 2019-04-26
        
        ### Added
        
        Features:
        
        - `TartifletteApp` ASGI application.
        - Built-in GraphiQL client.
        
        Project-related additions:
        
        - Package setup.
        - Changelog.
        - Contributing guide.
        - README and documentation.
        
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.6
Description-Content-Type: text/markdown
