Skip to content

Commit 9e876e5

Browse files
Merge pull request #8 from graphql-devise/customize-errors-extensions
Return errors using new GraphQL specification
2 parents e55b46a + 16984dc commit 9e876e5

7 files changed

Lines changed: 44 additions & 48 deletions

File tree

app/graphql/graphql_devise/mutations/base.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ module Mutations
55
class Base < GraphQL::Schema::Mutation
66
private
77

8+
def raise_user_error(message)
9+
raise GraphqlDevise::UserError, message
10+
end
11+
812
def remove_resource
913
controller.resource = nil
1014
controller.client_id = nil
1115
controller.token = nil
1216
end
1317

14-
def single_error_object(error)
15-
{ success: false, errors: [error] }
16-
end
17-
1818
def request
1919
controller.request
2020
end

app/graphql/graphql_devise/mutations/login.rb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ class Login < Base
44
argument :email, String, required: true
55
argument :password, String, required: true
66

7-
field :success, Boolean, null: false
8-
field :errors, [String], null: false
9-
107
def resolve(email:, password:)
118
resource = resource_class.find_by(email: email)
129

1310
if resource && active_for_authentication?(resource)
1411
if invalid_for_authentication?(resource, password)
15-
return single_error_object(I18n.t('graphql_devise.sessions.bad_credentials'))
12+
raise_user_error(I18n.t('graphql_devise.sessions.bad_credentials'))
1613
end
1714

1815
set_auth_headers(resource)
@@ -23,12 +20,12 @@ def resolve(email:, password:)
2320
{ success: true, authenticable: resource, errors: [] }
2421
elsif resource && !active_for_authentication?(resource)
2522
if locked?(resource)
26-
single_error_object(I18n.t('graphql_devise.mailer.unlock_instructions.account_lock_msg'))
23+
raise_user_error(I18n.t('graphql_devise.mailer.unlock_instructions.account_lock_msg'))
2724
else
28-
single_error_object(I18n.t('devise_token_auth.sessions.not_confirmed', email: resource.email))
25+
raise_user_error(I18n.t('devise_token_auth.sessions.not_confirmed', email: resource.email))
2926
end
3027
else
31-
single_error_object(I18n.t('graphql_devise.sessions.bad_credentials'))
28+
raise_user_error(I18n.t('graphql_devise.sessions.bad_credentials'))
3229
end
3330
end
3431

app/graphql/graphql_devise/mutations/logout.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
module GraphqlDevise
22
module Mutations
33
class Logout < Base
4-
field :success, Boolean, null: false
5-
field :errors, [String], null: false
6-
74
def resolve
85
if current_resource && client && current_resource.tokens[client]
96
current_resource.tokens.delete(client)
@@ -13,9 +10,9 @@ def resolve
1310

1411
yield current_resource if block_given?
1512

16-
{ success: true, errors: [], authenticable: current_resource }
13+
{ authenticable: current_resource }
1714
else
18-
{ success: false, errors: [I18n.t('graphql_devise.user_not_found')] }
15+
raise_user_error(I18n.t('graphql_devise.user_not_found'))
1916
end
2017
end
2118
end

lib/graphql_devise.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
module GraphqlDevise
88
class Error < StandardError; end
99
end
10+
11+
require 'graphql_devise/user_error'

lib/graphql_devise/user_error.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module GraphqlDevise
2+
class UserError < GraphQL::ExecutionError
3+
def to_h
4+
super.merge(extensions: { code: 'USER_ERROR' })
5+
end
6+
end
7+
end

spec/requests/mutations/login_spec.rb

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
password: "#{password}"
1414
) {
1515
user { email name signInCount }
16-
success
17-
errors
1816
}
1917
}
2018
GRAPHQL
@@ -28,10 +26,9 @@
2826
expect(response).to include_auth_headers
2927
expect(user.reload.tokens.keys).to include(response.headers['client'])
3028
expect(json_response[:data][:userLogin]).to match(
31-
success: true,
32-
errors: [],
33-
user: { email: user.email, name: user.name, signInCount: 1 }
29+
user: { email: user.email, name: user.name, signInCount: 1 }
3430
)
31+
expect(json_response[:errors]).to be_nil
3532
end
3633
end
3734

@@ -40,10 +37,9 @@
4037

4138
it 'returns bad credentials error' do
4239
expect(response).not_to include_auth_headers
43-
expect(json_response[:data][:userLogin]).to match(
44-
success: false,
45-
errors: ['Invalid login credentials. Please try again.'],
46-
user: nil
40+
expect(json_response[:data][:userLogin]).to be_nil
41+
expect(json_response[:errors]).to contain_exactly(
42+
hash_including(message: 'Invalid login credentials. Please try again.', extensions: { code: 'USER_ERROR' })
4743
)
4844
end
4945
end
@@ -54,13 +50,13 @@
5450

5551
it 'returns a must confirm account message' do
5652
expect(response).not_to include_auth_headers
57-
expect(json_response[:data][:userLogin]).to match(
58-
success: false,
59-
errors: [
60-
"A confirmation email was sent to your account at '#{user.email}'. You must follow the instructions in the " \
61-
"email before your account can be activated"
62-
],
63-
user: nil
53+
expect(json_response[:data][:userLogin]).to be_nil
54+
expect(json_response[:errors]).to contain_exactly(
55+
hash_including(
56+
message: "A confirmation email was sent to your account at '#{user.email}'. You must follow the " \
57+
"instructions in the email before your account can be activated",
58+
extensions: { code: 'USER_ERROR' }
59+
)
6460
)
6561
end
6662
end
@@ -70,10 +66,12 @@
7066

7167
it 'returns a must confirm account message' do
7268
expect(response).not_to include_auth_headers
73-
expect(json_response[:data][:userLogin]).to match(
74-
success: false,
75-
errors: ['Your account has been locked due to an excessive number of unsuccessful sign in attempts.'],
76-
user: nil
69+
expect(json_response[:data][:userLogin]).to be_nil
70+
expect(json_response[:errors]).to contain_exactly(
71+
hash_including(
72+
message: 'Your account has been locked due to an excessive number of unsuccessful sign in attempts.',
73+
extensions: { code: 'USER_ERROR' }
74+
)
7775
)
7876
end
7977
end
@@ -83,10 +81,9 @@
8381

8482
it 'returns a must confirm account message' do
8583
expect(response).not_to include_auth_headers
86-
expect(json_response[:data][:userLogin]).to match(
87-
success: false,
88-
errors: ['Invalid login credentials. Please try again.'],
89-
user: nil
84+
expect(json_response[:data][:userLogin]).to be_nil
85+
expect(json_response[:errors]).to contain_exactly(
86+
hash_including(message: 'Invalid login credentials. Please try again.', extensions: { code: 'USER_ERROR' })
9087
)
9188
end
9289
end

spec/requests/mutations/logout_spec.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
mutation {
1010
userLogout{
1111
authenticable { email }
12-
success
13-
errors
1412
}
1513
}
1614
GRAPHQL
@@ -25,21 +23,19 @@
2523
expect(response).not_to include_auth_headers
2624
expect(user.reload.tokens.keys).to be_empty
2725
expect(json_response[:data][:userLogout]).to match(
28-
success: true,
29-
errors: [],
3026
authenticable: { email: user.email }
3127
)
28+
expect(json_response[:errors]).to be_nil
3229
end
3330
end
3431

3532
context 'when user is not logged in' do
3633
it 'returns an error' do
3734
expect(response).not_to include_auth_headers
3835
expect(user.reload.tokens.keys).to be_empty
39-
expect(json_response[:data][:userLogout]).to match(
40-
success: false,
41-
errors: ['User was not found or was not logged in.'],
42-
authenticable: nil
36+
expect(json_response[:data][:userLogout]).to be_nil
37+
expect(json_response[:errors]).to contain_exactly(
38+
hash_including(message: 'User was not found or was not logged in.', extensions: { code: 'USER_ERROR' })
4339
)
4440
end
4541
end

0 commit comments

Comments
 (0)