Giter VIP home page Giter VIP logo

strawberry-graphql / strawberry Goto Github PK

View Code? Open in Web Editor NEW
3.8K 41.0 501.0 12.28 MB

A GraphQL library for Python that leverages type annotations ๐Ÿ“

Home Page: https://strawberry.rocks

License: MIT License

Python 99.36% HTML 0.32% Dockerfile 0.02% Shell 0.01% TypeScript 0.29%
graphql graphql-server python starlette asyncio mypy django graphql-library asgi graphql-schema strawberry hacktoberfest fastapi

strawberry's Introduction

Strawberry GraphQL

Python GraphQL library based on dataclasses

CircleCI Discord PyPI

Installation ( Quick Start )

The quick start method provides a server and CLI to get going quickly. Install with:

pip install "strawberry-graphql[debug-server]"

Getting Started

Create a file called app.py with the following code:

import strawberry


@strawberry.type
class User:
    name: str
    age: int


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        return User(name="Patrick", age=100)


schema = strawberry.Schema(query=Query)

This will create a GraphQL schema defining a User type and a single query field user that will return a hardcoded user.

To run the debug server run the following command:

strawberry server app

Open the debug server by clicking on the following link: http://0.0.0.0:8000/graphql

This will open GraphiQL where you can test the API.

Type-checking

Strawberry comes with a mypy plugin that enables statically type-checking your GraphQL schema. To enable it, add the following lines to your mypy.ini configuration:

[mypy]
plugins = strawberry.ext.mypy_plugin

Django Integration

A Django view is provided for adding a GraphQL endpoint to your application.

  1. Add the app to your INSTALLED_APPS.
INSTALLED_APPS = [
    ...,  # your other apps
    "strawberry.django",
]
  1. Add the view to your urls.py file.
from strawberry.django.views import GraphQLView
from .schema import schema

urlpatterns = [
    ...,
    path("graphql", GraphQLView.as_view(schema=schema)),
]

WebSockets

To support graphql Subscriptions over WebSockets you need to provide a WebSocket enabled server. The debug server can be made to support WebSockets with these commands:

pip install 'strawberry-graphql[debug-server]'
pip install 'uvicorn[standard]'

Examples

Contributing

We use poetry to manage dependencies, to get started follow these steps:

git clone https://github.com/strawberry-graphql/strawberry
cd strawberry
poetry install --with integrations
poetry run pytest

For all further detail, check out the Contributing Page

Pre commit

We have a configuration for pre-commit, to add the hook run the following command:

pre-commit install

Links

Licensing

The code in this project is licensed under MIT license. See LICENSE for more information.

Recent Activity

strawberry's People

Contributors

ambro17 avatar anoopmsivadas avatar bellini666 avatar botberry avatar brycebeagle avatar coady avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar devkral avatar doctorjohn avatar erikwrede avatar estyxx avatar flpstrri avatar g-as avatar jkimbo avatar kristjanvalur avatar la4de avatar lostb1t avatar marcoacierno avatar mgilson avatar nrbnlulu avatar ossareh avatar patrick91 avatar paulo-raca avatar pinkrespect avatar pre-commit-ci[bot] avatar skilkis avatar thejaminator avatar tsmith023 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

strawberry's Issues

Debug option for Django view

Would be nice to have the ability to see queries and responses directly from the django shell, I was trying to debug an error on CI and it would have been helpful :)

Convert field names to camel case

Currently, when creating a field with underscores it will be kept with underscores. We should convert them to camel case by default, and allow users to change that if they want :)

import strawberry

@strawberry.type
class Query:
    i_have_underscores: int = 2

print(repr(Query()))

Returns:

type Query {
  i_have_underscores: Int!
}

Subscriptions are returning data not wrapped into a field

It should return:

{
  "data": {
    "time": 1
  }
}

image

Repro:

from __future__ import annotations


import asyncio
import strawberry

@strawberry.type
class Query:
    hello: str = "demo"

@strawberry.type
class Subscription:
    @strawberry.subscription
    async def time(self, info) -> int:
        i = 0
        while True:
            yield i
            i += 1

            await asyncio.sleep(1)


schema = strawberry.Schema(
    query=Query, subscription=Subscription
)

Add Enum generation for Django choice fields

It would be great to support generating enum return types for Django CharFields where choices are defined. Currently strawberry resolves all CharField values to a String type.

We'll need to make sure that we don't define duplicate enum types or use names that would clash with other types in the schema.

See graphql-python/graphene-django#185 (comment) for a discussion about auto-generated choice enum types in Graphene.

Schema merging support for remote schemas

This might make Strawberry a good API gateway tool, the idea is to allow merging of multiple GraphQL schemas into one, and delegating the execution of queries to those APIs when requested.

The API might look like this:

import strawberry

schema_a = strawberry.remote_schema(
    "https://apollo-server.sse.codesandbox.io/grapqhl"
)

schema_b = strawberry.remote_schema(
    "https://apollo-server.sse.codesandbox.io/grapqhl"
)


schema = strawberry.merge_schemas([
    schema_a,
    schema_b
])

We might want to think of transforming the schemas when needed, for example when names are conflicting or when we want to add fields (extending types)

Mark arguments with default values as optional

import typing

import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, info, times: typing.Optional[int] = 1) -> str:
        return "Hello\n" * times


schema = strawberry.Schema(query=Query)

Add support for interfaces

We should be able to define interfaces with strawberry, something like this:

@strawberry.interface
class Node:
    id: strawberry.ID

Support for field permissions & visibility

Would be nice to have a simple way to require permission for specific fields and also hide them from the schema (visibility).

Permission example (borrowed from DRF)

import strawberry

from strawberry.permission import BasePermission


class IsAuthenticated(BasePermission):
    def has_permission(self, info) -> bool:
        return False


@strawberry.type
class User:
    name: str
    age: int


@strawberry.type
class Query:
    @strawberry.field(permission_classes=[IsAuthenticated])
    def me(self, info) -> Optional[User]:
        return User(name="Patrick", age=100)

Visibility example, what this should do is to completely hide the field from the schema if the client is not able to see it (so not even shown when doing introspection).

import strawberry

from strawberry.permission import BasePermission


class IsAdminClient(BasePermission):
    def has_permission(self, info) -> bool:
        return False


@strawberry.type
class User:
    name: str
    age: int


@strawberry.type
class Query:
    @strawberry.field(visiblity_classes=[IsAdminClient])
    def me(self, info) -> Optional[User]:
        return User(name="Patrick", age=100)

Support forward references

See: https://www.python.org/dev/peps/pep-0563/#forward-references

Right now the following code would break:

from __future__ import annotations

import strawberry
import typing

@strawberry.type
class User:
    name: str
    friend: typing.Optional[User]

This is the error we get:

  File "/Users/patrickarminio/Documents/personal/temp/stra/app.py", line 7, in <module>
    from schema import schema
  File "/Users/patrickarminio/Documents/personal/temp/stra/schema.py", line 10, in <module>
    @strawberry.type
  File "/Users/patrickarminio/.virtualenvs/stra-so-aNvo2/lib/python3.7/site-packages/strawberry/type.py", line 60, in type
    return wrap()
  File "/Users/patrickarminio/.virtualenvs/stra-so-aNvo2/lib/python3.7/site-packages/strawberry/type.py", line 55, in wrap
    cls._fields = _get_fields(cls)
  File "/Users/patrickarminio/.virtualenvs/stra-so-aNvo2/lib/python3.7/site-packages/strawberry/type.py", line 27, in _get_fields
    cls_annotations = typing.get_type_hints(cls)
  File "/Users/patrickarminio/.pyenv/versions/3.7.0/lib/python3.7/typing.py", line 973, in get_type_hints
    value = _eval_type(value, base_globals, localns)
  File "/Users/patrickarminio/.pyenv/versions/3.7.0/lib/python3.7/typing.py", line 260, in _eval_type
    return t._evaluate(globalns, localns)
  File "/Users/patrickarminio/.pyenv/versions/3.7.0/lib/python3.7/typing.py", line 464, in _evaluate
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
NameError: name 'User' is not defined

Add SDL to strawberry conversion tool

It would be nice to have a command to convert an SDL to strawberry types, something like:

type User {
  name: String!
}

type Query {
  user: User
}
$ strawberry import-schema path.grapqhl
import typing
import strawberry

@strawberry.type
class User:
    name: str

@strawberry.type
class Query:
    user: typing.Optional[User]

This should support description and directives if possible :)

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Lightning Talk on Strawberry

i watched the excellent talk on GraphQL and strawberry at EuroPython 1019. This library makes a lot of sense to me. But sadly people want 5 minute lightning talks. Has anyone created one. I want to add it to PythonLinks.info.

ASGI app broken with asyncio

Our ASGI app is currently broken with async io stuff. The implementation I made needs a bit of love :) We might have a look at how Ariadne is doing this :)

Here's a test that fails:

import typing

import pytest

import strawberry
from starlette.testclient import TestClient
from strawberry.asgi import GraphQL


@pytest.fixture
def async_schema():
    @strawberry.type
    class Query:
        @strawberry.field
        async def hello(self, info, name: typing.Optional[str] = None) -> str:
            return f"Hello {name or 'world'}"

    return strawberry.Schema(Query)


@pytest.fixture
def test_client(async_schema):
    app = GraphQL(async_schema)

    return TestClient(app)


def test_simple_query(schema, test_client):
    response = test_client.post("/", json={"query": "{ hello }"})

    assert response.json() == {"data": {"hello": "Hello world"}}

Update wiki

Because GitHub does not support PR's against wikis, please review the changes at:
https://github.com/agritheory/strawberrywiki

I added what was to me the next obvious step, which was documenting interactions with the strawberry dev server.

I plan to continue to add add tutorial-ish pages, next with a nested data example and a fragment.

Document release process

Currently only me and @marcoacierno know that we can automatically release strawberry on PyPI. We should document this, and maybe make a bot that suggests to add a Release file :)

Add integration for flask and quart

Any plans for implementations targeting flask or quart?

Alternatively, is there a standard way a third party could write a plugin for strawberry that targets an alternative framework? Asking because I like the design of strawberry models, but switching the entire framework leads to a pretty big migration rather than just swapping out graphene.

Types representation is not helpful

Currently the representations for types and enums aren't really helpful, especially while debugging:

>>> import strawberry
>>> @strawberry.input
... class Example:
...     arg: str
...
>>> Example
<class '__main__.Example'>
>>> x = Example("abc")
>>> x
input Example {
  arg: String!
}

I think we should move the current representation to be used only when using the class and not an instance, for the instances we can keep what dataclasses is giving us:

>>> @dataclasses.dataclass()
... class Example:
...     arg: str
...
>>> Example("abc")
Example(arg='abc')

Custom scalars

Sometimes it's useful to define custom scalar types in your schema, the examples I can think of right now are DateTime and Date.

That's how I implemented them in a project

DateTime = NewType("DateTime", str)


def serialize_datetime(value):
    return value.isoformat()


def parse_value_datetime(value):
    return parse_datetime(value)


def parse_literal_datetime(ast, _variables=None):
    if not isinstance(ast, StringValueNode):
        return INVALID

    try:
        return parse_datetime(ast.value)
    except ValueError:
        return INVALID


REGISTRY[DateTime] = GraphQLScalarType(
    name="DateTime",
    description="Date with time (isoformat)",
    serialize=serialize_datetime,
    parse_value=parse_value_datetime,
    parse_literal=parse_literal_datetime,
)

It would be cool to have a decorator like strawberry.scalar that allows you to automatically define and register a new type + scalar:

@strawberry.scalar
class DateTime:
    ???

I'm not sure how the interface might look to define serialize, parse_value and parse_literal.

This is how it's implemented in Graphene: https://github.com/graphql-python/graphene/blob/master/graphene/types/datetime.py

I feel like parse_literal can be implemented on a strawberry level by simply doing something like:

if typing == str:
   # Check that the AST is a StringValue and then call parse_value
elif typing == int:
   # Check that the AST is a int type and then call parse_value

While serialize and parse_value have to be implemented custom in the scalar

@strawberry.scalar
class DateTime:
    @staticmethod
    def serialize(value):
        return value.isoformat()

    @staticmethod
    def parse_value(value):
       return parse_datetime(value)

To make it easier to understand we might want to call them to_python and from_python. But.. it doesn't really look good :)

We also need to change the type resolution system to support a class as scalar

@strawberry.scalar
class Always5(int):
    @staticmethod
    def from_python(value):
        return 5

    @staticmethod
    def to_python(value):
        if value != 5:
            return None

        return 5


@strawberry.type
class Query:
    hey: Always5 = 10

Add Graphene compatibility

It would be awesome to be able to incrementally adopt strawberry types into an existing Graphene project. That way users don't have to re-write their existing GraphQL APIs if they want to try strawberry.

Perhaps we could create a way for users to merge Graphene and strawberry schemas, and serve the combined schema from a single endpoint.

This may be easier to implement now that both libraries use graphql-core-next under the hood (as of graphene v3).

Add support for renaming fields

We should be able to specify a custom name for a field when needed, like this:

@strawberry.type
class Query:
    example_field: str = strawberry.field(name="example")

Improve starting message for dev server

Right now it doesn't tell the user that the dev server is running, and it also shows this message which is not really helpful:

Starting monitor for PID 27242.

Move CI to GitHub actions and add tests on windows

There's a PR open for this, might be worth picking it up again: #148

So we can use GitHub Actions to run tests on windows as well as linux and Mac OS :)

TODO

  • Run release on github actions (currently it is on circle ci)
  • Run tests on windows

Expose DirectiveLocation from strawberry.directives

Our changelog has this example for directives:

import strawberry
from strawberry.directives import DirectiveLocation

@strawberry.type
class Query:
    cake: str = "made_in_switzerland"

@strawberry.directive(
    locations=[DirectiveLocation.FIELD], description="Make string uppercase"
)
def uppercase(value: str, example: str):
    return value.upper()

schema = strawberry.Schema(query=Query, directives=[uppercase])

but we don't have strawberry.directives package :)

Add support for description in fields

@strawberry.type
class Query:
    @strawberry.field
    async def todos(self, info) -> typing.List[str]:
        """A list of TODOs"""
        return ["a", "b"]
@strawberry.type
class Query:
    @strawberry.field(description="A list of TODOs")
    async def todos(self, info) -> typing.List[str]:
        return ["a", "b"]

We also need a way to define descriptions on simple fields

@strawberry.type
class TODO:
    id: strawberry.ID
    """This would be unique"""
@strawberry.type
class TODO:
    id: str = strawberry.field(description="This would be unique")

See:

Add custom return type annotation for subscriptions

Currently it appears that when defining a subscription the return type annotation must be set to typing.AsyncGenerator[str, None], like so:

@strawberry.type
class Subscription:
    @strawberry.subscription
    async def time(self, info) -> typing.AsyncGenerator[str, None]:
        ...

Do we need to use typing.AsyncGenerator as the return type for subscription definitions? I'm not sure that I love that dev experience. Would it be bad practice to use raw types as the return type? Something like:

@strawberry.subscription
async def time(self, info) -> str:
    ...

Or maybe a we could use a custom return type for subscriptions:

@strawberry.subscription
async def time(self, info) -> strawberry.subscription_result(str):
    ...

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Mutation level permissions

It would be great to have a way to specify permissions for a mutation, something similar to what we did for the fields

Lists being marked as Optional

When defining a list the resulting schema marks the list as optional (or nullable in GraphQL terms) even if it wasn't wrapped in typing.Optional, we should fix that :)

Setup docs with mkdocs

https://www.mkdocs.org

A friend of mine is working on a design for the new website which will also include the docs, but for now I think we can start with mkdocs. The new website will pull the documentation from this repo so no work will be wasted in case we start this before the new website :)

Add Django Support

I'd love to see strawberry support Django as a first class citizen via a contrib package. To start, it could be as simple as adding a Django view that exposes a GraphQL endpoint and the GraphQL Playground. From there, a lot of other neat features could be added, such as:

  • Django authentication integration
  • Out of the box subscription support using Django channels
  • Automatic type generation from Django models
  • Automatic CRUD query / mutation / subscription generation for Django models

Is this something that strawberry would be interested in supporting?

Apollo Federation Support

I was thinking of adding support for Apollo Federation, in order to make this happen the following TODOs need to be tackled:

  • Allow support for custom directives #109
    not really true, but having a pythonic way of defining directives will help
  • Output types in schema even if they are not used by a query
    Right now we only output fields that are used (directly and indirectly) in a query. Federated schemas might not define a query at all, so we need to output types anyway.
  • Add support for custom scalars #3

Federation specification

scalar _Any
scalar _FieldSet

# a union of all types that use the @key directive
union _Entity

type _Service {
  sdl: String
}

extend type Query {
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
}

directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE

directive @extends on OBJECT | INTERFACE

Federation spec: https://www.apollographql.com/docs/apollo-server/federation/federation-spec/

Python API

Initial Ideas

type Review {
  body: String
  author: User @provides(fields: "username")
  product: Product
}

extend type User @key(fields: "id") {
  id: ID! @external
  reviews: [Review]
}

extend type Product @key(fields: "upc") {
  upc: String! @external
  reviews: [Review]
}
@strawberry.type
class Review:
  body: str
  author: User = strawberry.field(directives=[provides(fields="username")])
  product: Product


@strawberry.type(extend=True, directives=[key(fields="id")])
class User:
  id: ID = strawberry.field(directives=[external()])
  reviews: typing.list[Review]


@strawberry.type(extend=True, directives=[key(fields="upc")])
class Product:
  upc: str = strawberry.field(directives=[external()])
  reviews: typing.list[Review]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.