In the last episode we saw how to set up our app. In this episode, we already have all our models up and running. We will start testing our API.
Project
Testing our API + Docs
We need to write tests for our API. We also need to document it for other developers. With RSpec API Documentation , we can do both at the same time. It has a DSL that generates documentation while verifying that the API works as described, all at once. Let's take a look!
By default all the tests are inside the
spec/acceptance
folder. Here we can
see an example:
require 'spec_helper'
require 'rspec_api_documentation/dsl'
resource "Orders" do
get "/orders" do
example "Listing orders" do
do_request
status.should == 200
end
end
end
In this example we describe the
Orders
resource. We're describing how you can
GET /orders
. The
example
method receives a string explaining what the
request is for, and the method
do_request
performs the request that's
described.
We will create a helper for our tests. That will be located in the
spec
folder. We will call this
acceptance_helper
and we will use it in acceptance
tests.
# frozen_string_literal: true
require 'rails_helper'
require 'rspec_api_documentation'
require 'rspec_api_documentation/dsl'
RspecApiDocumentation.configure do |config|
config.format = :json
config.post_body_formatter = :json
config.curl_host = 'http://localhost:3000'
config.api_name = 'Formulae API'
end
In this file, we will set up our API name, its base URL, how our
POST
body
should be formatted, and many other options described in the documentation.
Let's create a test for our
Question
and we will use the
acceptance_helper
we
have just created.
We will use the routes we have. If you don't know the route to what you're
documenting, you can run
rake routes
to find out.
get '/api/v1/questions/' do
example 'Listing all the questions' do
do_request
expect(status).to eq 200
end
end
For this test, we're starting very simple. We'll just check if the response code
is 200. Our second test will be to check our
show
method.
get '/api/v1/questions/:id' do
example 'Getting a specific Question' do
do_request
response = JSON.parse(response_body)
expect(response.keys).to eq %w[id key label content order hidden]
expect(status).to eq 200
end
end
In this case, we:
- make a request
- read the response body
- parse it as JSON
- make sure it has the keys we expect
-
ensure we get a
200 OKHTTP status.
This is a useful test and
rspec_api_documentation
made it easy to document
and test the request. We are checking the keys
id
,
key
,
label
,
content
,
order
, and
hidden
. Let's run our tests.
Our test has failed because we are also returning
created_at
and
updated_at
.
Let's add these fields in our test.
After adding them, our tests pass.
Let's do a test to show we can update a question. We'll update the
key
:
put '/api/v1/questions/:id' do
parameter :key, scope: :question
let(:new_value) { 'updated' }
let(:key) { new_value }
example_request 'Updating a question' do
response = JSON.parse(response_body)
expect(response['label']). to eq q.label
expect(response['key']). to eq new_value
expect(status).to eq(200)
end
end
We are describing a parameter for the API call, and using
rspec
's
let
to
pass the parameter. We're scoping the parameter inside a
question
key. This
describes the JSON we're
POST
ing. The
id
is taken from another
let
that
specifies the
id
of a
Question
we created in preparation for the test,
earlier in the file.
In our test, we pass a new value for our key and we verify that the JSON is returning this new value. Our test passes!
Let's do a test to check our
delete
method. If a question is deleted, we
return 204, so, in our tests we will check exactly this.
delete '/api/v1/questions/:id' do
example_request 'Deleting a question' do
expect(status).to eq(204)
end
end
The methods of this DSL - like
example_request
,
parameter
, and others - are
used when generate the documentation. This way, while we are writing tests for
our API we are also creating our documentation.
Our tests pass!
To generate our documentation we just need to run a rake task that updates it for us:
rake docs:generate
And then we can open the generated docs:
open doc/api/index.html
There are various viewers we can use - one is APItome - to improve how our docs look.
Serializers
We are already returning some JSON from our API, but we would like to have more control over how it will look. To achieve this, we will use a library that handles serializers for us: Active Model Serializers . It helps us more easily describe our JSON response shape and manage how our JSON looks, even when we have associations between our models.
Let's add
active_model_serializers
in our
Gemfile
and run a
bundle
. Now we
will create a serializer for our
Question
. In our serializer we will add only
the fields we want to show in our JSON.
This is how you can have control over what your JSON will look like. You can
create your own serializer or decorator, of course, without this library - but
it's a fair bit of work. Here
active_model_serializers
helps us a lot!
In our questions controller, we are returning
created_at
and
updated_at
, but
we don't want to return them. In this case, we will just not add these in our
serializer.
We will create our Question serializer in
/app/serializers/
, and we will
create our serializer without
id
,
created_at
and
updated_at
.
frozen_string_literal: true
class QuestionSerializer < ActiveModel::Serializer
attributes :key, :label, :content, :order, :hidden
end
Let's change our test. It passes!
If we want to change the fields, we just need to change the
QuestionSerializer
and it will use the attributes we want. This is pretty handy: in all the places
the question is returned, it will call the serializer.
For example, if we add or remove the
id
for our Question, and we refresh the
result, we can see it! The same thing happens if we remove the
key
.
Summary
In this episode we saw how to test our API, and used those tests to generate
documentation for our API, using
rspec_api_documentation
. We also saw how to
create serializers for our API with
active_model_serializers
to help us
control how our JSON responses look. I hope you enjoyed it. See you soon!
Comments for Testing and Documenting our API