In my rest framework user registration form I successfully created a custom registration form and added some validators. It shows corresponding validation errors in rest framework.but when linked this to react through redux it gets the error but not showing corresponding validation errors like " A user is already registered with this e-mail address. ". The rest showsit like this.
JSON format that gets at react is this
error: {
message: 'Request failed with status code 400',
name: 'Error',
fileName: 'http://localhost:3000/static/js/1.chunk.js',
lineNumber: 871,
columnNumber: 15,
stack: 'createError@http://localhost:3000/static/js/1.chunk.js:871:15\nsettle@http://localhost:3000/static/js/1.chunk.js:1092:12\nhandleLoad@http://localhost:3000/static/js/1.chunk.js:346:13\nEventHandlerNonNull*dispatchXhrRequest@http://localhost:3000/static/js/1.chunk.js:322:5\nxhrAdapter@http://localhost:3000/static/js/1.chunk.js:301:10\ndispatchRequest@http://localhost:3000/static/js/1.chunk.js:924:10\npromise callback*request@http://localhost:3000/static/js/1.chunk.js:712:23\nforEachMethodWithData/Axios.prototype[method]@http://localhost:3000/static/js/1.chunk.js:736:17\nwrap@http://localhost:3000/static/js/1.chunk.js:1252:15\nsignUp/<@http://localhost:3000/static/js/main.chunk.js:3406:50\ncreateThunkMiddleware/</</<@http://localhost:3000/static/js/1.chunk.js:40096:18\ndispatch@http://localhost:3000/register:1:28546\nonAuth@http://localhost:3000/static/js/main.chunk.js:3305:110\nRegMain/this.handlesubmit@http://localhost:3000/static/js/main.chunk.js:2684:62\ncallCallback@http://localhost:3000/static/js/1.chunk.js:8030:18\ninvokeGuardedCallbackDev@http://localhost:3000/static/js/1.chunk.js:8079:20\ninvokeGuardedCallback@http://localhost:3000/static/js/1.chunk.js:8132:35\ninvokeGuardedCallbackAndCatchFirstError@http://localhost:3000/static/js/1.chunk.js:8147:29\nexecuteDispatch@http://localhost:3000/static/js/1.chunk.js:8232:46\nexecuteDispatchesInOrder@http://localhost:3000/static/js/1.chunk.js:8257:24\nexecuteDispatchesAndRelease@http://localhost:3000/static/js/1.chunk.js:11141:33\nexecuteDispatchesAndReleaseTopLevel@http://localhost:3000/static/js/1.chunk.js:11150:14\nforEachAccumulated@http://localhost:3000/static/js/1.chunk.js:11122:12\nrunEventsInBatch@http://localhost:3000/static/js/1.chunk.js:11167:25\nrunExtractedPluginEventsInBatch@http://localhost:3000/static/js/1.chunk.js:11377:23\nhandleTopLevel@http://localhost:3000/static/js/1.chunk.js:11421:40\nbatchedEventUpdates$1@http://localhost:3000/static/js/1.chunk.js:29567:16\nbatchedEventUpdates@http://localhost:3000/static/js/1.chunk.js:8639:16\ndispatchEventForLegacyPluginEventSystem@http://localhost:3000/static/js/1.chunk.js:11431:28\nattemptToDispatchEvent@http://localhost:3000/static/js/1.chunk.js:12151:48\ndispatchEvent@http://localhost:3000/static/js/1.chunk.js:12072:45\nunstable_runWithPriority@http://localhost:3000/static/js/1.chunk.js:41893:16\nrunWithPriority$1@http://localhost:3000/static/js/1.chunk.js:18917:14\ndiscreteUpdates$1@http://localhost:3000/static/js/1.chunk.js:29584:16\ndiscreteUpdates@http://localhost:3000/static/js/1.chunk.js:8652:16\ndispatchDiscreteEvent@http://localhost:3000/static/js/1.chunk.js:12051:22\nEventListener.handleEvent*addEventBubbleListener@http://localhost:3000/static/js/1.chunk.js:11905:15\ntrapEventForPluginEventSystem@http://localhost:3000/static/js/1.chunk.js:12045:31\ntrapBubbledEvent@http://localhost:3000/static/js/1.chunk.js:12015:36\nsetInitialProperties@http://localhost:3000/static/js/1.chunk.js:13826:27\nfinalizeInitialChildren@http://localhost:3000/static/js/1.chunk.js:15351:27\ncompleteWork@http://localhost:3000/static/js/1.chunk.js:26705:44\ncompleteUnitOfWork@http://localhost:3000/static/js/1.chunk.js:29895:20\nperformUnitOfWork@http://localhost:3000/static/js/1.chunk.js:29868:16\nworkLoopSync@http://localhost:3000/static/js/1.chunk.js:29833:26\nperformSyncWorkOnRoot@http://localhost:3000/static/js/1.chunk.js:29451:13\nscheduleUpdateOnFiber@http://localhost:3000/static/js/1.chunk.js:28883:32\nupdateContainer@http://localhost:3000/static/js/1.chunk.js:32032:19\nlegacyRenderSubtreeIntoContainer/<@http://localhost:3000/static/js/1.chunk.js:32415:26\nunbatchedUpdates@http://localhost:3000/static/js/1.chunk.js:29601:16\nlegacyRenderSubtreeIntoContainer@http://localhost:3000/static/js/1.chunk.js:32414:25\nrender@http://localhost:3000/static/js/1.chunk.js:32497:14\n./src/index.js@http://localhost:3000/static/js/main.chunk.js:4166:50\n__webpack_require__@http://localhost:3000/static/js/bundle.js:785:30\nfn@http://localhost:3000/static/js/bundle.js:151:20\n1@http://localhost:3000/static/js/main.chunk.js:4181:18\n__webpack_require__@http://localhost:3000/static/js/bundle.js:785:30\ncheckDeferredModules@http://localhost:3000/static/js/bundle.js:46:23\nwebpackJsonpCallback@http://localhost:3000/static/js/bundle.js:33:19\n@http://localhost:3000/static/js/main.chunk.js:1:71\n',
config: {
url: 'http://127.0.0.1:8000/rest-auth/register/',
method: 'post',
data: '{"fname":"Abhiram","lname":"PS","username":"rooteeee","phone":"8589967868","email":"abhirampjayan@outlook.com","cemail":"abhirampjayan@outlook.com","password1":"abhi1998","password2":"abhi1998","gender":"M","acctype":"Student"}',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8'
},
transformRequest: [
null
],
transformResponse: [
null
],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1
}
}
source code of serializer.py is given bellow
from rest_framework import serializers
from accounts.models import Account
from allauth.account import app_settings as allauth_settings
from allauth.utils import email_address_exists
from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email
from rest_framework.validators import UniqueValidator
from rest_framework.response import Response
from rest_framework import status
class CustomUserDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('pk','email','fname','lname','username','phone','gender','acctype')
#read_only_fields = ('email','acctype','fname','lname')
class CustomRegisterSerializer(serializers.Serializer):
fname = serializers.CharField(required=True, write_only=True)
lname = serializers.CharField(required=True, write_only=True)
username = serializers.CharField(min_length=allauth_settings.USERNAME_MIN_LENGTH,required=allauth_settings.USERNAME_REQUIRED,validators=[UniqueValidator(queryset=Account.objects.all(),message='A user is already registered with this Username.')])
phone=serializers.CharField(required=True, write_only=True,min_length=10,max_length=10)
email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
cemail = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
password1 = serializers.CharField(write_only=True, required=True)
password2 = serializers.CharField(write_only=True, required=True)
acctype=serializers.ChoiceField(['Student','Staff'])
gender=serializers.ChoiceField([('M','M'),('F','F')])
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(("A user is already registered with this e-mail address."))
return email
def validate_password1(self, password):
return get_adapter().clean_password(password)
def validate(self, data):
if data['password1'] != data['password2']:
raise serializers.ValidationError(("The password fields didn't match."))
if data['email'] !=data['cemail']:
raise serializers.ValidationError(("The email fields didn't match."))
return data
def get_cleaned_data(self):
return {
'fname': self.validated_data.get('fname', ''),
'lname': self.validated_data.get('lname', ''),
'username': self.validated_data.get('username', ''),
'acctype': self.validated_data.get('acctype', ''),
'gender': self.validated_data.get('gender', ''),
'phone': self.validated_data.get('phone', ''),
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
}
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
user.fname=self.cleaned_data.get('fname')
user.lname=self.cleaned_data.get('lname')
user.phone=self.cleaned_data.get('phone')
user.acctype=self.cleaned_data.get('acctype')
user.gender=self.cleaned_data.get('gender')
user.save()
return user
redux action creators file(auth.js) is given below
import * as actionTypes from './actionTypes'
import axios from 'axios'
export const authStart=()=>{
return{
type:actionTypes.AUTH_START
}
}
export const authSuccess=(token)=>{
return{
type:actionTypes.AUTH_SUCCESS,
token:token
}
}
export const authFail=(error)=>{
return{
type:actionTypes.AUTH_FAIL,
error:error
}
}
export const checkAuthTimeout = expirationTime =>{
return disaptch=>{
setTimeout(()=>{
disaptch(logout())
},expirationTime * 1000)
}
}
export const autLlogout=()=>{
return{
type:actionTypes.AUTH_LOGOUT
}
}
export const authLogin=(username,password)=>{
return disaptch=>{
disaptch(authStart())
axios.post('http://127.0.0.1:8000/rest-auth/login/',{
username:username,
password:password
}).then(res=>{
const token=res.data.key
const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
localStorage.setItem('token',token)
localStorage.setItem('expirationDate',expirationDate)
disaptch(authSuccess(token))
disaptch(checkAuthTimeout(3600))
}).catch(err=>{
disaptch (authFail(err))
})
}
}
export const signUp=(fname,lname,username,phone,email,cemail,password1,password2,gender,acctype)=>{
return disaptch=>{
disaptch(authStart())
axios.post('http://127.0.0.1:8000/rest-auth/register/',{
fname:fname,
lname:lname,
username:username,
phone:phone,
email:email,
cemail:cemail,
password1:password1,
password2:password2,
gender:gender,
acctype:acctype,
}).then(res=>{
const token=res.data.key
const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
localStorage.setItem('token',token)
localStorage.setItem('expirationDate',expirationDate)
disaptch(authSuccess(token))
disaptch(checkAuthTimeout(3600))
}).catch(err=>{
disaptch (authFail(err))
})
}
}
export const logout=()=>{
localStorage.removeItem('uesr')
localStorage.removeItem('expirationDate')
return {
type:actionTypes.AUTH_LOGOUT
}
}
export const authCheckState=()=>{
return disaptch=>{
const token=localStorage.getItem('token')
if(token===undefined){
disaptch(logout())
}else{
const expirationDate=new Date(localStorage.getItem('expirationDate'))
if(expirationDate<=new Date()){
disaptch(logout())
}else{
disaptch(authSuccess(token))
disaptch(checkAuthTimeout((expirationDate.getTime()-new Date().getTime())/1000))
}
}
}
}
On first glance, this issue looks to be in react layer:
Axios will treat the 400 status code response as an error, and rather than resolve the promise and determine response data, will throw the error you are seeing above.
One way to handle this:
axios.create({
// ...vars
responseType: "json",
validateStatus: status => {
// handling our own errors less than 500 status
return status < 500;
},
headers: headers
});
when creating the initial axios client. This will cause axios to not throw an error.
Then, within your promise .then(res=>{...})
you will need to check the response status code for 400, and process errors accordingly.
Code:
export const authLogin=(username,password)=>{
return dispatch=>{
dispatch(authStart())
axios.post('http://127.0.0.1:8000/rest-auth/login/',{
username:username,
password:password
}, {
validateStatus: status => {return status < 500}
}).then(res=>{
if (res.status === 400) {
// Will have validation errors on response body
dispatch(authFail(res.data))
} else {
const token=res.data.key
const expirationDate = new Date(new Date().getTime() + 3600 * 1000)
localStorage.setItem('token',token)
localStorage.setItem('expirationDate',expirationDate)
dispatch(authSuccess(token))
dispatch(checkAuthTimeout(3600))
}
}).catch(err=>{
dispatch (authFail(err))
})
}
}