Skip to content

Revise documentation #969

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions UPGRADE-v1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@

Big changes from v0.10.x to 1.0. While on the surface a lot of this just looks like shuffling around API, the entire codebase has been rewritten to handle some really great use cases and improved performance.


## Backwards Compatibility and Deprecation Warnings

This has been a community project from the start, we need your help making the upgrade as smooth as possible for everybody!
We have done our best to provide backwards compatibility with deprecated APIs.


## Deprecations

* `with_context` is no longer needed. Resolvers now always take the context argument.
- `with_context` is no longer needed. Resolvers now always take the context argument.
Before:

```python
def resolve_xxx(self, args, info):
def resolve_xxx(root, args, info):
# ...
```

With 1.0:

```python
def resolve_xxx(self, args, context, info):
def resolve_xxx(root, args, context, info):
# ...
```

* `ObjectType` and `Interface` no longer accept the `abstract` option in the `Meta`.
- `ObjectType` and `Interface` no longer accept the `abstract` option in the `Meta`.
Inheriting fields should be now achieved using `AbstractType` inheritance.

Before:
Expand All @@ -42,6 +41,7 @@ We have done our best to provide backwards compatibility with deprecated APIs.
```

With 1.0:

```python
class MyBaseQuery(graphene.AbstractType):
my_field = String()
Expand All @@ -50,9 +50,9 @@ We have done our best to provide backwards compatibility with deprecated APIs.
pass
```

* The `type_name` option in the Meta in types is now `name`
- The `type_name` option in the Meta in types is now `name`

* Type references no longer work with strings, but with functions.
- Type references no longer work with strings, but with functions.

Before:

Expand All @@ -70,7 +70,6 @@ We have done our best to provide backwards compatibility with deprecated APIs.
users = graphene.List(lambda: User)
```


## Schema

Schemas in graphene `1.0` are `Immutable`, that means that once you create a `graphene.Schema` any
Expand All @@ -80,7 +79,6 @@ The `name` argument is removed from the Schema.
The arguments `executor` and `middlewares` are also removed from the `Schema` definition.
You can still use them, but by calling explicitly in the `execute` method in `graphql`.


```python
# Old way
schema = graphene.Schema(name='My Schema')
Expand All @@ -94,7 +92,6 @@ schema = graphene.Schema(
)
```


## Interfaces

For implementing an Interface in an ObjectType, you have to add it onto `Meta.interfaces`.
Expand Down Expand Up @@ -131,7 +128,7 @@ class ReverseString(Mutation):

reversed = String()

def mutate(self, args, context, info):
def mutate(root, args, context, info):
reversed = args.get('input')[::-1]
return ReverseString(reversed=reversed)

Expand All @@ -158,14 +155,13 @@ class Query(ObjectType):
Also, if you wanted to create an `ObjectType` that implements `Node`, you have to do it
explicity.


## Django

The Django integration with Graphene now has an independent package: `graphene-django`.
For installing, you have to replace the old `graphene[django]` with `graphene-django`.

* As the package is now independent, you now have to import from `graphene_django`.
* **DjangoNode no longer exists**, please use `relay.Node` instead:
- As the package is now independent, you now have to import from `graphene_django`.
- **DjangoNode no longer exists**, please use `relay.Node` instead:

```python
from graphene.relay import Node
Expand All @@ -181,8 +177,8 @@ For installing, you have to replace the old `graphene[django]` with `graphene-dj
The SQLAlchemy integration with Graphene now has an independent package: `graphene-sqlalchemy`.
For installing, you have to replace the old `graphene[sqlalchemy]` with `graphene-sqlalchemy`.

* As the package is now independent, you have to import now from `graphene_sqlalchemy`.
* **SQLAlchemyNode no longer exists**, please use `relay.Node` instead:
- As the package is now independent, you have to import now from `graphene_sqlalchemy`.
- **SQLAlchemyNode no longer exists**, please use `relay.Node` instead:

```python
from graphene.relay import Node
Expand Down
72 changes: 35 additions & 37 deletions UPGRADE-v2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ It also improves the field resolvers, [simplifying the code](#simpler-resolvers)
developer has to write to use them.

**Deprecations:**
* [`AbstractType`](#abstracttype-deprecated)
* [`resolve_only_args`](#resolve_only_args)
* [`Mutation.Input`](#mutationinput)

- [`AbstractType`](#abstracttype-deprecated)
- [`resolve_only_args`](#resolve_only_args)
- [`Mutation.Input`](#mutationinput)

**Breaking changes:**
* [`Simpler Resolvers`](#simpler-resolvers)
* [`Node Connections`](#node-connections)

- [`Simpler Resolvers`](#simpler-resolvers)
- [`Node Connections`](#node-connections)

**New Features!**
* [`InputObjectType`](#inputobjecttype)
* [`Meta as Class arguments`](#meta-as-class-arguments) (_only available for Python 3_)

- [`InputObjectType`](#inputobjecttype)
- [`Meta as Class arguments`](#meta-as-class-arguments) (_only available for Python 3_)

> The type metaclasses are now deleted as they are no longer necessary. If your code was depending
> The type metaclasses are now deleted as they are no longer necessary. If your code was depending
> on this strategy for creating custom attrs, see an [example on how to do it in 2.0](https://github.com/graphql-python/graphene/blob/v2.0.0/graphene/tests/issues/test_425.py).

## Deprecations
Expand Down Expand Up @@ -49,7 +51,7 @@ class Pet(CommonFields, Interface):
pass
```

### resolve\_only\_args
### resolve_only_args

`resolve_only_args` is now deprecated as the resolver API has been simplified.

Expand All @@ -60,8 +62,8 @@ class User(ObjectType):
name = String()

@resolve_only_args
def resolve_name(self):
return self.name
def resolve_name(root):
return root.name
```

With 2.0:
Expand All @@ -70,8 +72,8 @@ With 2.0:
class User(ObjectType):
name = String()

def resolve_name(self, info):
return self.name
def resolve_name(root, info):
return root.name
```

### Mutation.Input
Expand All @@ -94,7 +96,6 @@ class User(Mutation):
name = String()
```


## Breaking Changes

### Simpler resolvers
Expand All @@ -108,7 +109,7 @@ Before:
```python
my_field = graphene.String(my_arg=graphene.String())

def resolve_my_field(self, args, context, info):
def resolve_my_field(root, args, context, info):
my_arg = args.get('my_arg')
return ...
```
Expand All @@ -118,23 +119,23 @@ With 2.0:
```python
my_field = graphene.String(my_arg=graphene.String())

def resolve_my_field(self, info, my_arg):
def resolve_my_field(root, info, my_arg):
return ...
```

**PS.: Take care with receiving args like `my_arg` as above. This doesn't work for optional (non-required) arguments as stantard `Connection`'s arguments (first, before, after, before).**
You may need something like this:

```python
def resolve_my_field(self, info, known_field1, known_field2, **args): ## get other args with: args.get('arg_key')
def resolve_my_field(root, info, known_field1, known_field2, **args): ## get other args with: args.get('arg_key')
```

And, if you need the context in the resolver, you can use `info.context`:

```python
my_field = graphene.String(my_arg=graphene.String())

def resolve_my_field(self, info, my_arg):
def resolve_my_field(root, info, my_arg):
context = info.context
return ...
```
Expand Down Expand Up @@ -188,6 +189,7 @@ class MyObject(ObjectType):
```

To:

```python
class MyObject(ObjectType):
class Meta:
Expand All @@ -203,30 +205,32 @@ class MyObject(ObjectType):
The parameters' order of `get_node_from_global_id` method has changed. You may need to adjust your [Node Root Field](http://docs.graphene-python.org/en/latest/relay/nodes/#node-root-field) and maybe other places that uses this method to obtain an object.

Before:

```python
class RootQuery(object):
...
node = Field(relay.Node, id=ID(required=True))

def resolve_node(self, args, context, info):
def resolve_node(root, args, context, info):
node = relay.Node.get_node_from_global_id(args['id'], context, info)
return node
```

Now:

```python
class RootQuery(object):
...
node = Field(relay.Node, id=ID(required=True))

def resolve_node(self, info, id):
def resolve_node(root, info, id):
node = relay.Node.get_node_from_global_id(info, id)
return node
```

## Mutation.mutate

Now only receives (`self`, `info`, `**args`) and is not a @classmethod
Now only receives (`root`, `info`, `**kwargs`) and is not a @classmethod

Before:

Expand All @@ -245,7 +249,7 @@ With 2.0:
class SomeMutation(Mutation):
...

def mutate(self, info, **args):
def mutate(root, info, **args):
...
```

Expand All @@ -258,17 +262,14 @@ class SomeMutation(Mutation):
last_name = String(required=True)
...

def mutate(self, info, first_name, last_name):
def mutate(root, info, first_name, last_name):
...
```



## ClientIDMutation.mutate_and_get_payload

Now only receives (`root`, `info`, `**input`)


### Middlewares

If you are using Middelwares, you need to some adjustments:
Expand All @@ -294,10 +295,9 @@ class MyGrapheneMiddleware(object):
## Middleware code

info.context = context
       return next_mw(root, info, **args)```
       return next_mw(root, info, **args)
```


## New Features

### InputObjectType
Expand All @@ -321,7 +321,7 @@ class Query(ObjectType):
user = graphene.Field(User, input=UserInput())

@resolve_only_args
def resolve_user(self, input):
def resolve_user(root, input):
user_id = input.get('id')
if is_valid_input(user_id):
return get_user(user_id)
Expand All @@ -334,18 +334,17 @@ class UserInput(InputObjectType):
id = ID(required=True)

@property
def is_valid(self):
return self.id.startswith('userid_')
def is_valid(root):
return root.id.startswith('userid_')

class Query(ObjectType):
user = graphene.Field(User, input=UserInput())

def resolve_user(self, info, input):
def resolve_user(root, info, input):
if input.is_valid:
return get_user(input.id)
```


### Meta as Class arguments

Now you can use the meta options as class arguments (**ONLY PYTHON 3**).
Expand All @@ -366,7 +365,6 @@ class Dog(ObjectType, interfaces=[Pet]):
name = String()
```


### Abstract types

Now you can create abstact types super easily, without the need of subclassing the meta.
Expand All @@ -378,10 +376,10 @@ class Base(ObjectType):

id = ID()

def resolve_id(self, info):
def resolve_id(root, info):
return "{type}_{id}".format(
type=self.__class__.__name__,
id=self.id
type=root.__class__.__name__,
id=root.id
)
```

Expand Down
8 changes: 4 additions & 4 deletions docs/execution/dataloader.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ leaner code and at most 4 database requests, and possibly fewer if there are cac
best_friend = graphene.Field(lambda: User)
friends = graphene.List(lambda: User)

def resolve_best_friend(self, info):
return user_loader.load(self.best_friend_id)
def resolve_best_friend(root, info):
return user_loader.load(root.best_friend_id)

def resolve_friends(self, info):
return user_loader.load_many(self.friend_ids)
def resolve_friends(root, info):
return user_loader.load_many(root.friend_ids)
Loading