Skip to content

Commit eb3986d

Browse files
rosaclaude
andcommitted
Add JSON format support to signup flow for native API clients
The magic link verification endpoint now returns `requires_signup_completion` to indicate whether the client needs to collect a name and complete signup. The signup completion endpoint now supports JSON responses with the account ID. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent c059e0b commit eb3986d

File tree

4 files changed

+58
-6
lines changed

4 files changed

+58
-6
lines changed

app/controllers/sessions/magic_links_controller.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def sign_in(magic_link)
4646

4747
respond_to do |format|
4848
format.html { redirect_to after_sign_in_url(magic_link) }
49-
format.json { render json: { session_token: session_token } }
49+
format.json { render json: { session_token: session_token, requires_signup_completion: requires_signup_completion? } }
5050
end
5151
end
5252

@@ -68,7 +68,7 @@ def invalid_code
6868
end
6969

7070
def after_sign_in_url(magic_link)
71-
if magic_link.for_sign_up?
71+
if requires_signup_completion?
7272
new_signup_completion_path
7373
else
7474
after_authentication_url
@@ -82,4 +82,8 @@ def rate_limit_exceeded
8282
format.json { render json: { message: rate_limit_exceeded_message }, status: :too_many_requests }
8383
end
8484
end
85+
86+
def requires_signup_completion?
87+
magic_link.for_sign_up?
88+
end
8589
end

app/controllers/signups/completions_controller.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@ def create
1111
@signup = Signup.new(signup_params)
1212

1313
if @signup.complete
14-
flash[:welcome_letter] = true
15-
redirect_to landing_url(script_name: @signup.account.slug)
14+
respond_to do |format|
15+
format.html do
16+
flash[:welcome_letter] = true
17+
redirect_to landing_url(script_name: @signup.account.slug)
18+
end
19+
format.json { render json: { account_id: @signup.account.external_account_id }, status: :created }
20+
end
1621
else
17-
render :new, status: :unprocessable_entity
22+
respond_to do |format|
23+
format.html { render :new, status: :unprocessable_entity }
24+
format.json { render json: { errors: @signup.errors.full_messages }, status: :unprocessable_entity }
25+
end
1826
end
1927
end
2028

test/controllers/sessions/magic_links_controller_test.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class Sessions::MagicLinksControllerTest < ActionDispatch::IntegrationTest
8080
assert MagicLink.exists?(expired_link.id), "Expired magic link should not be consumed"
8181
end
8282

83-
test "create via JSON" do
83+
test "create via JSON for sign in" do
8484
identity = identities(:david)
8585
magic_link = identity.send_magic_link
8686

@@ -89,6 +89,20 @@ class Sessions::MagicLinksControllerTest < ActionDispatch::IntegrationTest
8989
post session_magic_link_path(format: :json), params: { code: magic_link.code }
9090
assert_response :success
9191
assert @response.parsed_body["session_token"].present?
92+
assert_equal false, @response.parsed_body["requires_signup_completion"]
93+
end
94+
end
95+
96+
test "create via JSON for sign up" do
97+
identity = identities(:david)
98+
magic_link = identity.send_magic_link(for: :sign_up)
99+
100+
untenanted do
101+
post session_path(format: :json), params: { email_address: identity.email_address }
102+
post session_magic_link_path(format: :json), params: { code: magic_link.code }
103+
assert_response :success
104+
assert @response.parsed_body["session_token"].present?
105+
assert_equal true, @response.parsed_body["requires_signup_completion"]
92106
end
93107
end
94108

test/controllers/signup/completions_controller_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,30 @@ class Signup::CompletionsControllerTest < ActionDispatch::IntegrationTest
5555
assert_select "li", text: "Full name can't be blank"
5656
end
5757
end
58+
59+
test "create via JSON" do
60+
untenanted do
61+
post signup_completion_path(format: :json), params: {
62+
signup: {
63+
full_name: @signup.full_name
64+
}
65+
}
66+
end
67+
68+
assert_response :created
69+
assert @response.parsed_body["account_id"].present?
70+
end
71+
72+
test "create via JSON with blank name" do
73+
untenanted do
74+
post signup_completion_path(format: :json), params: {
75+
signup: {
76+
full_name: ""
77+
}
78+
}
79+
end
80+
81+
assert_response :unprocessable_entity
82+
assert_includes @response.parsed_body["errors"], "Full name can't be blank"
83+
end
5884
end

0 commit comments

Comments
 (0)