Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render 400-500 status response HTML #39

Merged
merged 1 commit into from
Dec 30, 2020
Merged

Conversation

seanpdoyle
Copy link
Contributor

@seanpdoyle seanpdoyle commented Dec 26, 2020

Related to hotwired/turbo-rails#12
Related to hotwired/turbo-rails#34

Typically, Turbo expects each FormSubmission request to result in a
redirect to a new Location.

When a FormSubmission request fails with an HTTP Status code between
400-499 or 500-599 (e.g. unprocessable entity), render the
response HTML. This commit brings the same behavior to <turbo-frame>
elements.

@@ -99,7 +99,9 @@ export class FormSubmission {
}

requestSucceededWithResponse(request: FetchRequest, response: FetchResponse) {
if (this.requestMustRedirect(request) && !response.redirected) {
if (response.unprocessableEntity) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only special case status we want to support?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to cover all 4xx errors, not only 422. 422 is pretty specific to rails scaffolding conventions where as 4xx is more widely used for forms that have errors.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

422 is problematic also for Rails. Default HTML response for invalid form is 200, 422 is usually used only for JSON responses. I know it can be changed, but support for default behaviour would be nicer :).

Example from rails scaffold generator:

  # POST /rooms
  # POST /rooms.json
  def create
    @room = Room.new(room_params)

    respond_to do |format|
      if @room.save
        format.html { redirect_to @room, notice: 'Room was successfully created.' }
        format.json { render :show, status: :created, location: @room }
      else
        format.html { render :new }
        format.json { render json: @room.errors, status: :unprocessable_entity }
      end
    end
  end

@Intrepidd
Copy link
Contributor

Note : I realised that form submits sent by turbo don't have the Turbo-Frameheader. This header helps telling the backend this is a frame request. Rails for instance doesn't render the layout if this is a frame request. Should we send this header now that we accept a frame response back ?

if (this.requestMustRedirect(request) && !response.redirected) {
if (response.unprocessableEntity) {
this.delegate.formSubmissionFailedWithResponse(this, response)
} else if (this.requestMustRedirect(request) && !response.redirected) {
const error = new Error("Form responses must redirect to another location")
Copy link

@santib santib Dec 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the technical reason why we need to have this error triggered when the response is not a redirect?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the technical reason why we need to have this error triggered when the response is not a redirect?

#22 (comment)

@seanpdoyle seanpdoyle changed the title Render 422 Response HTML Render 400-500 status response HTML Dec 29, 2020
Copy link
Contributor

@sstephenson sstephenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. I agree with your choice to expand this to cover all 4xx and 5xx responses.

src/core/drive/navigator.ts Outdated Show resolved Hide resolved
Related to hotwired/turbo-rails#12
Related to hotwired/turbo-rails#34

Typically, Turbo expects each FormSubmission request to result in a
redirect to a new Location.

When a FormSubmission request fails with an HTTP Status code between
400-499 or 500-599 (e.g. [unprocessable entity][422]), render the
response HTML. This commit brings the same behavior to `<turbo-frame>`
elements.

[422]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422
@sstephenson sstephenson merged commit 4227383 into main Dec 30, 2020
@sstephenson sstephenson deleted the form-submission-422 branch December 30, 2020 21:38
const responseHTML = await fetchResponse.responseHTML

if (responseHTML) {
debugger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤠

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Intrepidd
Copy link
Contributor

For long forms, page is not scrolled to the top after submit, do you think this should be fixed natively in turbo ?

carlosantoniodasilva added a commit to heartcombo/responders that referenced this pull request Jan 16, 2021
When responding to an HTML request that had errors on the resource,
responders would not set any status, which means Rails would default to
`200 OK`. This has been long working like this but also a long
discussion in responders to change that behavior, to be more inline with
how other types of requests (like JSON/XML) handle responses by setting
the HTTP status to 422 Unprocessable Entity when responding with an
error.

More recently with the Turbo/Hotwire library, they've added support to
render form responses as errors with 4xx statuses [1], so it makes even
more sense for responders to make the move here.

This change now makes it respond with 422 Unprocessable Entity in such
cases when the resource has errors, and should work more out of the box
with Turbo/Hotwire.

Please note that this is a possible breaking change if you're relying on
the previous status to trigger any behavior for errors in your app.

[1] hotwired/turbo#39
carlosantoniodasilva added a commit to heartcombo/responders that referenced this pull request Jan 16, 2021
When responding to a non-GET HTML request that had errors on the
resource, responders would not set any status, which means Rails would
default to `200 OK`. This has been long working like this but also a
long discussion in responders to change that behavior, to be more inline
with how other types of requests (like JSON/XML) handle responses by
setting the HTTP status to 422 Unprocessable Entity when responding with
an error.

More recently with the Turbo/Hotwire library, they've added support to
render form responses as errors with 4xx statuses [1], so it makes even
more sense for responders to make the move here.

This change now makes responders use the 422 Unprocessable Entity status
in such cases when the resource has errors, and should work more out of
the box with Turbo/Hotwire.

Please note that this is a possible breaking change if you're relying on
the previous status to trigger any behavior for errors in your app.

[1] hotwired/turbo#39
fabpot added a commit to symfony/symfony that referenced this pull request Jan 17, 2021
…appropriate HTTP status code (dunglas)

This PR was squashed before being merged into the 5.3-dev branch.

Discussion
----------

[FrameworkBundle] Add renderForm() helper setting the appropriate HTTP status code

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | yes <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | n/a
| License       | MIT
| Doc PR        | todo

A 422 HTTP status code should be returned after the submission of an invalid form. Some libraries including [Turbo](hotwired/turbo#39) rely on this behavior and will not display the updated form (containing errors) unless this status code is present.

Rails also [recently switched to this behavior ](rails/rails#41026) by default for the same reason.

I propose to introduce a new helper method rendering the form and setting the appropriate status code. It makes the code cleaner:

```php
// src/Controller/TaskController.php

// ...
use Symfony\Component\HttpFoundation\Request;

class TaskController extends AbstractController
{
    public function new(Request $request): Response
    {
        $task = new Task();
        $form = $this->createForm(TaskType::class, $task);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $task = $form->getData();
            // ...

            return $this->redirectToRoute('task_success');
        }

        return $this->renderForm('task/new.html.twig', $form);
    }
}
```

Commits
-------

4c77e50 [FrameworkBundle] Add renderForm() helper setting the appropriate HTTP status code
airblade added a commit to airblade/quo_vadis that referenced this pull request Jun 1, 2021
This is required by Turbo [1].
This will be the default in Rails 7 [2].

[1] hotwired/turbo#39
[2] rails/rails@2afc905
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants