# v2.0 Upgrade Guide

`ObjectType`, `Interface`, `InputObjectType`, `Scalar` and `Enum` implementations
have been quite simplified, without the need to define a explicit Metaclass for each subtype.

It also improves the field resolvers, [simplifying the code](#simpler-resolvers) the
developer has to write to use them.

**Deprecations:**

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

**Breaking changes:**

- [`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_)

> 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

### AbstractType deprecated

AbstractType is deprecated in graphene 2.0, you can now use normal inheritance instead.

Before:

```python
class CommonFields(AbstractType):
    name = String()

class Pet(CommonFields, Interface):
    pass
```

With 2.0:

```python
class CommonFields(object):
    name = String()

class Pet(CommonFields, Interface):
    pass
```

### resolve_only_args

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

Before:

```python
class User(ObjectType):
    name = String()

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

With 2.0:

```python
class User(ObjectType):
    name = String()

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

### Mutation.Input

`Mutation.Input` is now deprecated in favor of using `Mutation.Arguments` (`ClientIDMutation` still uses `Input`).

Before:

```python
class User(Mutation):
    class Input:
        name = String()
```

With 2.0:

```python
class User(Mutation):
    class Arguments:
        name = String()
```

## Breaking Changes

### Simpler resolvers

All the resolvers in graphene have been simplified.
Prior to Graphene `2.0`, all resolvers required four arguments: `(root, args, context, info)`.
Now, resolver `args` are passed as keyword arguments to the function, and `context` argument dissapeared in favor of `info.context`.

Before:

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

def resolve_my_field(root, args, context, info):
    my_arg = args.get('my_arg')
    return ...
```

With 2.0:

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

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 standard `Connection`'s arguments (first, last, after, before).**
You may need something like this:

```python
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(root, info, my_arg):
    context = info.context
    return ...
```

### Node Connections

Node types no longer have a `Connection` by default.
In 2.0 and onwards `Connection`s should be defined explicitly.

Before:

```python
class User(ObjectType):
    class Meta:
        interfaces = [relay.Node]
    name = String()

class Query(ObjectType):
    user_connection = relay.ConnectionField(User)
```

With 2.0:

```python
class User(ObjectType):
    class Meta:
        interfaces = [relay.Node]
    name = String()

class UserConnection(relay.Connection):
    class Meta:
        node = User

class Query(ObjectType):
    user_connection = relay.ConnectionField(UserConnection)
```

## Node.get_node

The method `get_node` in `ObjectTypes` that have `Node` as interface, changes its API.
From `def get_node(cls, id, context, info)` to `def get_node(cls, info, id)`.

```python
class MyObject(ObjectType):
    class Meta:
        interfaces = (Node, )

    @classmethod
    def get_node(cls, id, context, info):
        return ...
```

To:

```python
class MyObject(ObjectType):
    class Meta:
        interfaces = (Node, )

    @classmethod
    def get_node(cls, info, id):
        return ...
```

## Node.get_node_from_global_id

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(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(root, info, id):
        node = relay.Node.get_node_from_global_id(info, id)
        return node
```

## Mutation.mutate

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

Before:

```python
class SomeMutation(Mutation):
    ...

    @classmethod
    def mutate(cls, instance, args, context, info):
        ...
```

With 2.0:

```python
class SomeMutation(Mutation):
    ...

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

With 2.0 you can also get your declared (as above) `args` this way:

```python
class SomeMutation(Mutation):
    class Arguments:
        first_name = String(required=True)
        last_name = String(required=True)
    ...

    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:

Before:

```python
class MyGrapheneMiddleware(object):
    def resolve(self, next_mw, root, args, context, info):

        ## Middleware code

        return next_mw(root, args, context, info)
```

With 2.0:

```python
class MyGrapheneMiddleware(object):
    def resolve(self, next_mw, root, info, **args):
        context = info.context

        ## Middleware code

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

## New Features

### InputObjectType

If you are using `InputObjectType`, you now can access
its fields via `getattr` (`my_input.myattr`) when resolving, instead of
the classic way `my_input['myattr']`.

And also use custom defined properties on your input class.

Example. Before:

```python
class UserInput(InputObjectType):
    id = ID(required=True)

def is_valid_input(input):
    return input.get('id').startswith('userid_')

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

    @resolve_only_args
    def resolve_user(root, input):
        user_id = input.get('id')
        if is_valid_input(user_id):
            return get_user(user_id)
```

With 2.0:

```python
class UserInput(InputObjectType):
    id = ID(required=True)

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

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

    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**).

Before:

```python
class Dog(ObjectType):
    class Meta:
        interfaces = [Pet]
    name = String()
```

With 2.0:

```python
class Dog(ObjectType, interfaces=[Pet]):
    name = String()
```

### Abstract types

Now you can create abstact types super easily, without the need of subclassing the meta.

```python
class Base(ObjectType):
    class Meta:
        abstract = True

    id = ID()

    def resolve_id(root, info):
        return f"{root.__class__.__name__}_{root.id}"
```

### UUID Scalar

In Graphene 2.0 there is a new dedicated scalar for UUIDs, `UUID`.