pythondjangographqldjango-graphql-jwt

GraphQL: [Errno 111] Connection refused


Description

I am trying to build an API for a transportation system which has different kind of users (Driver, Customer, SystemAdmin and Authorizer). For this purpose I created an AbstractUser and use inheritance relationship for the all of the above different users. For adding JWT to the model, I have read the official tutorial, but whenever I want to create a new user like the following I faced to the error:

mutation {
  register(
    email: "new_user@email.com",
    username: "new_user",
    password1: "supersecretpassword",
    password2: "supersecretpassword",
  ) {
    success,
    errors,
    token,
    refreshToken
  }
}

Steps to Reproduce

  1. Here is my model:
from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class Usermodel(AbstractUser, models.Model):
    phone_no = models.CharField(
        max_length=11,
        blank=True,
        verbose_name="Phone Number"
    )

    USERNAME_FIELD = "username"   # e.g: "username", "email"
    EMAIL_FIELD = "email"         # e.g: "email", "primary_email"
    
    def __str__(self):
        return self.username

    
class Driver(Usermodel, models.Model):
    national_id = models.CharField(
        max_length=10, 
        blank=True, 
        verbose_name="National ID"
    )

    profile_picture = models.ImageField(
        blank=True,
        null=True
    )

    STATUS_CHOICES = [
        ('1', 'Free'),
        ('2', 'Busy')
    ]

    driver_status = models.CharField(
        max_length=1,
        choices=STATUS_CHOICES
    )

    rating = models.FloatField(
        default=-1
    )

    ranking = models.IntegerField(
        default=-1
    )

    class Meta:
        verbose_name = 'Driver'
        verbose_name_plural = 'Drivers'

class Authorizer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Authorizer'
        verbose_name_plural = 'Authorizers'

class Customer(Usermodel, models.Model):
    class Meta:
        verbose_name = 'Customer'
        verbose_name_plural = 'Customers'

class Administrator(Usermodel, models.Model):
    class Meta:
        verbose_name='Adminsitrator'
        verbose_name_plural='Administrators'
  1. users schema
import graphene
from graphene import Mutation, ObjectType, InputObjectType
from .models import Driver, Authorizer, Customer, Administrator
from graphene_django.types import DjangoObjectType


class DriverType(DjangoObjectType):
    class Meta:
        model = Driver

class AuthorizerType(DjangoObjectType):
    class Meta:
        model = Authorizer

class Query(ObjectType):
    driver = graphene.Field(
        DriverType,
        id = graphene.ID()
    )

    authorizer = graphene.Field(
        AuthorizerType,
        id = graphene.ID()
    )

    all_drivers = graphene.List(DriverType)
    all_authorizers = graphene.List(AuthorizerType)

    def resolve_all_drivers(self, info, **kwargs):
        return Driver.objects.all()

    def resolve_driver(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_authorizer(self, info, **kwargs):
        id = kwargs.get('id')
        if id is not None:
            return Driver.objects.get(pk=id)

    def resolve_all_authorizers(self, info, **kwargs):
        return Authorizer.objects.all()


class DriverInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    national_id = graphene.String()
    password = graphene.String()


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()
class CreateDriver(Mutation):
    class Arguments:
        driver_data = DriverInput()
        
    driver = graphene.Field(DriverType)

    def mutate(self, info, driver_data=None):
        driver = Driver(
            first_name=driver_data.first_name,
            last_name=driver_data.last_name,
            email=driver_data.email,
            username=driver_data.username,
            phone_no=driver_data.phone_no,
            national_id=driver_data.national_id,
            password=driver_data.password
        )

        driver.save()

        return CreateDriver(
            driver=driver
        )

class UpdateDriver(Mutation):
    class Arguments:
        id = graphene.ID()
        driver_data = DriverInput()
    
    driver = graphene.Field(DriverType)

    def mutate(self, info, id, driver_data=None):
        #TODO: Error handling if the id not exists
        driver = Driver.objects.get(pk=id)

        driver.first_name = driver_data.first_name
        driver.last_name = driver_data.last_name
        driver.email = driver_data.email
        driver.username = driver_data.username
        driver.phone_no = driver_data.phone_no
        driver.national_id = driver_data.national_id
        driver.password = driver_data.password
        driver.save()

        return UpdateDriver(driver=driver)


class AuthorizerInput(InputObjectType):
    first_name = graphene.String()
    last_name = graphene.String()
    email = graphene.String()
    username = graphene.String()
    phone_no = graphene.String()
    password = graphene.String()

class CreateAuthorizer(Mutation):
    class Arguments:
        authorizer_data = AuthorizerInput()

    authorizer = graphene.Field(AuthorizerInput)

    def mutate(self, info, authorizer_data=None):
        authorizer = Authorizer(
            firstname=authorizer_data.first_name,
            last_name=authorizer_data.last_name,
            email=authorizer_data.email,
            username=authorizer_data.username,
            phone_no=authorizer_data.phone_no,
            password=authorizer_data.password
        )
        authorizer.save()
        return CreateAuthorizer(authorizer=authorizer)

class UpdateAuthorizer(Mutation):
    class Arguments:
        id = graphene.ID()
        authorizer_data = AuthorizerInput()
    
    authorizer = graphene.Field(AuthorizerType)
    
    def mutate(self, info, id, authorizer_data=None):
        authorizer = Authorizer.objects.get(pk=id)
        authorizer.first_name = authorizer_data.first_name
        authorizer.last_name = authorizer_data.last_name
        authorizer.email = authorizer_data.email
        authorizer.username = authorizer_data.username
        authorizer.password = authorizer_data.password
        authorizer.save()

        return UpdateDriver(authorizer=authorizer)

class Mutations(ObjectType):
    create_driver = CreateDriver.Field()
    update_driver = UpdateDriver.Field()

  1. project schema
import graphene

from apps.users.schema import Query as user_query
from apps.users.schema import Mutations as user_mutation
from graphql_auth.schema import UserQuery, MeQuery
from graphql_auth import mutations

class AuthMutation(graphene.ObjectType):
   register = mutations.Register.Field()


class Query(user_query, UserQuery, MeQuery):
    pass

class Mutations(user_mutation, AuthMutation):
    pass    

schema = graphene.Schema(
    query=Query,
    mutation=Mutations
)

Expected behavior

I expect the code to run without any problem but face to the following error in actual behavior

I also have another question. As I have explained for the various kind of user and registration of them, I need different arguments. But in schema we just add register = mutations.Register.Field(), How can I reach to this purpose?

Actual behavior

error description

Requirements

aniso8601==7.0.0
asgiref==3.2.10
Django==3.0.8
django-filter==2.3.0
django-graphql-auth==0.3.11
django-graphql-jwt==0.3.0
graphene==2.1.8
graphene-django==2.12.1
graphql-core==2.3.2
graphql-relay==2.0.1
Pillow==7.2.0
pkg-resources==0.0.0
promise==2.3
PyJWT==1.7.1
pytz==2020.1
Rx==1.6.1
singledispatch==3.4.0.3
six==1.15.0
sqlparse==0.3.1
Unidecode==1.1.1

Solution

  • Question 1: I expect the code to run without any problem but face to the following error in actual behavior

    N.B. It's going to be a little difficult to answer this without seeing how your settings.py is configured, but double-check that you went through every step. I went through the quickstart too but still missed a few spots.

    A: Make sure you have your settings.py properly configured

    I ran into a similar "Connection refused" error, but the issue was that my settings were not configured properly.

    Edit: After further local development and toggling with individual settings, I realized that my "Connection refused error was related to not having EMAIL_BACKEND configured. It was trying to connect to any SMTP server that wasn't running. Make sure you have EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" set to log this functionality to your console.

    Here's a slightly abbreviated copy of my settings.py from a scratch project I was using, just to be sure that you have it configured correctly:

    Source: django-graphql-auth quickstart.

    N.B.: It's a little long, make sure to scroll all the way through

    # ...
    
    
    # Application definition
    
    INSTALLED_APPS = [
        "django.contrib.admin",
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.messages",
        "django.contrib.staticfiles",
        
        # Package apps
        "corsheaders",
        "graphene_django",
        "graphql_jwt.refresh_token.apps.RefreshTokenConfig",
        "graphql_auth",
        "django_filters",
    
        # Created apps
        "users", # or whatever the name of the app is with your custom users model
    ]
    
    MIDDLEWARE = [
        "django.middleware.security.SecurityMiddleware",
        "django.contrib.sessions.middleware.SessionMiddleware",
        "corsheaders.middleware.CorsMiddleware",
        "django.middleware.common.CommonMiddleware",
        "django.middleware.csrf.CsrfViewMiddleware",
        "django.contrib.auth.middleware.AuthenticationMiddleware",
        "django.contrib.messages.middleware.MessageMiddleware",
        "django.middleware.clickjacking.XFrameOptionsMiddleware",
    ]
    
    ROOT_URLCONF = "<project_name>.urls"
    
    # TEMPLATES = ...
    # WSGI_APPLICATION = ...
    # DATABASES = ...
    
    # Ensure that custom user is set
    AUTH_USER_MODEL = "users.CustomUser"
    
    # AUTH_PASSWORD_VALIDATORS = ...
    
    # Internationalization
    # https://docs.djangoproject.com/en/3.0/topics/i18n/
    
    # ...
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.0/howto/static-files/
    # ...
    
    GRAPHENE = {
        "SCHEMA": "backend.schema.schema",
        "MIDDLEWARE": ["graphql_jwt.middleware.JSONWebTokenMiddleware",],
    }
    
    AUTHENTICATION_BACKENDS = [
        "graphql_jwt.backends.JSONWebTokenBackend",
        "django.contrib.auth.backends.ModelBackend",
        "graphql_auth.backends.GraphQLAuthBackend",
    ]
    
    GRAPHQL_JWT = {
        "JWT_VERIFY_EXPIRATION": True,
        "JWT_LONG_RUNNING_REFRESH_TOKEN": True,
    }
    
    EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
    

    Question 2: As I have explained for the various kind of user and registration of them, I need different arguments. But in schema we just add register = mutations.Register.Field(), How can I reach to this purpose?

    A: TLDR - this is explained in the dynamic fields section of the settings docs.

    A: Walkthrough

    Step 1: Make sure that your custom user model has the field set

    Before we think about updating our settings, confirm that the custom field you need to set exists on the model. For example, if I wanted to have a luck_number field, I would add:

    class CustomUser(AbstractUser):
        ...
    
        luck_number = models.IntegerField()
        ...
    
    

    Then you need to make sure you run migrations so that this exists in your database. python manage.py makemigrations python manage.py migrate

    Step 2: Add GRAPHQL_AUTH to settings.py

    In your settings, make sure to set:

    # Rest of your settings ...
    
    GRAPHQL_AUTH = {}
    
    

    Step 3: Add your custom fields and double-check your schema

    If you want to add fields to collect on registration, you need to add the REGISTER_MUTATION_FIELDS to your GRAPHQL_AUTH settings. So in the case of adding luck_number to our register mutation:

    GRAPHQL_AUTH = {
      REGISTER_MUTATION_FIELDS = {
        "email": "String",
        "username": "String",
        "luck_number": "Int",
      }
    }
    
    register mutation with custom field

    edit 1: adding image

    edit 2: adding clarification around my error on register mutation