18 July 2020
Welcome to the fifth chapter of the API-only ruby on rails course. In this chapter, we will introduce the
Renderer module for the API controllers. If you haven’t read the previous chapters yet, you can check the content list from the course page.
As you remember from the previous chapters, we have a user creation endpoint as following.
Even though we only have one action at the moment, we will have the same behavior for other endpoints. If the desired condition is done successfully, we would like to render the JSON representation of the resource along with the HTTP status code. Otherwise, we want to render the JSON representation of the errors for the resource. If the endpoint has only one possible path like getting the resource information, we will again use the first approach.
Instead of writing
render json: @user, status: :created and
render json: @user.errors, status: :unprocessable_entity every time in the controllers, we can extract those code blocks to the specific methods called
render_errors. We can then place them to a separate module to be able to use from different API controllers and have a single place to structure all API payloads. It will also make it easy to add metadata information for the payloads, which we will cover in the next chapter.
We will build the
renderer module while refactoring the
create action of the users controller, but we will do it with small iterations and check the tests to feel confident enough about our changes.
Let’s start with creating a concern file (
app/controllers/concerns/renderer.rb) and implement
render_object method as a first step.
render_object method, we basically get the resource object and render them as we were doing in the users controller. We also used
:ok status as a default parameter, since most of the API responses will return HTTP 200 status code. Now let’s use the
render_object method from the users controller. (Do not forget to include
Now, we can run user request spec to see if everything still works as before.
Since everything works as expected, we can do the same enhancement with the
Here we passed
unprocessable_entity as a default value of the status parameter, which is 422 HTTP status code. And again, let’s refactor the
create action of the users controller.
And again, let’s run user request spec to see tests are still green.
All tests are passed, perfect! As you can see, we refactor our
create action confidently since we have proper request tests. As a general rule of thumb, it’s good to check whether you have corresponding specs before refactoring any place in the codebase.
We included the
renderer module inside of the users controller, but we need to move it to the base controller because we will use that functionality also from other API controllers, which are extended by the base controller.
We already checked requests specs for the user controller but we also need to write necessary tests for the renderer module itself. Let’s create
spec/concerns/renderer_spec.rb file and start with writing spec for the
Here, we created an anonymous rails controller extended by
ApplicationController and included the
Renderer module. Then we built a show action that uses the
render_object method with the user resource. And later, we defined the controller spec for the anonymous controller we created, and we sent a request to check if the
render_object method returns the expected resource payload along with the correct HTTP status code.
Now we can extend same approach for the
We tried to create a user record with invalid parameters with the create action, and then we returned validation errors with the
render_errors method. Similar to the
render_object test, we send a request to
create action and checked if it has the correct payload with the status code.
Let’s run renderer specs to see everything is working as intended.
You might have realized that we have a
Metrics/BlockLength rubocop offense for
renderer_spec.rb file since rspec block has too many lines. But since it’s actually the DSL of the rspec, I want to exclude spec directory from this rule.
Before finishing the chapter, let’s run all specs to make sure we didn’t break any existing behavior of the application.
In this chapter, we introduced the
renderer module and refactored the create action of users controller by using
render_errors methods. In the next chapter, we will improve the
renderer module to have a better API payload structure, and we will add metadata information to the API responses. You can find the source code of bookmarker application on github. You can also find the previous chapter here.
Thank you for reading! If you want to be notified when I publish a new chapter, you can follow me on twitter.