How to write tests with RSpecApi
RSpecApi extends the DSL provided by RSpec with the following methods:
resource
describes a RESTful API resourceget
,post
,put
,patch
, anddelete
indicate the actions available on the resourcerespond_with
sends a request to the API and verifies that the response meets the expectationshas_attribute
lists the expected attributes in the response bodyaccept
allows to make parametrized requests for filters, sorting, pagination and callbackshost
andadapter
specify how to access the API, either locally or remotelyauthorize_with
provides authentication credentials to the requestthrottle
prevents ‘Too Many Requests’ errors
The next example introduced on Page 1 will be the starting point to illustrate these methods and how to use them:
concerts_spec.rbresource :concert do
host 'http://myconcerts.herokuapp.com'
has_attribute :id, type: {number: :integer}
has_attribute :where, type: :string
has_attribute :website, type: [:null, string: :url]
get '/concerts', collection: true do
respond_with :ok
end
post '/concerts' do
respond_with :created, concert: {where: 'Coachella'}
respond_with :unprocessable_entity, concert: {where: nil}
end
end
resource
RSpecApi makes some assumptions on the web APIs to be tested, based on a set of popular best practices.
The first assumption is that the API should follow the key principles of REST, which
“… involve separating your API into logical resources. These resources are manipulated using HTTP requests where the method (GET, POST, PUT, PATCH, DELETE) has specific meaning.”
The method resource
helps separate API tests by resource, as in:
resource :concert do
# Here list the actions to access a concert resource
# e.g. get '/concerts', post '/concerts', delete '/concerts/:id'
end
resource :artist do
# Here list the actions to access an artist resource
# e.g. patch '/artists/:id', get '/country/:country/artists'
end
There is not a lot of magic in this method: a look at its source code
reveals how it is mostly syntactic sugar around RSpec’s describe
. The code above is indeed equivalent to:
describe "Concerts" do
extend RSpecApi::Resource
# Here list the actions to access a concert resource
# e.g. get '/concerts', post '/concerts', delete '/concerts/:id'
end
describe "Artists" do
extend RSpecApi::Resource
# Here list the actions to access an artist resource
# e.g. patch '/artists/:id', get '/country/:country/artists'
end
In short, resource
creates an example group to describe an API resource,
and makes available inside that group the methods get
, post
, put
, patch
, and delete
of RSpecApi::Resource
which are detailed hereafter.
get
, post
, put
, patch
, delete
The next best practice that RSpecApi expects from an API is that resources can be accessed with HTTP methods:
“Once you have your resources defined, you need to identify what actions apply to them and how those would map to your API. RESTful principles provide strategies to handle CRUD actions using HTTP methods […] GET, POST, PUT, PATCH, DELETE.”
The methods get
, post
, put
, patch
, and delete
help describe the actions available for each resource, as in:
resource :concert do
get '/concerts', collection: true do
# Here describe the expectations of GET /concerts
end
post '/concerts' do
# Here describe the expectations of POST /concerts
end
end
There is not a lot of magic in these methods either: a look at the source code
reveals how they are mostly syntactic sugar around RSpec’s describe
. The code above is indeed equivalent to:
resource :concert do
describe "Retrieving a list of concerts", rspec_api_params: {action: :get, route: "/concerts", collection: true} do
extend RSpecApi::Requests
# Here describe the expectations of GET /concerts
end
describe "Creating one concert", rspec_api_params: {action: :post, route: "/concerts"} do
extend RSpecApi::Requests
# Here describe the expectations of POST /concerts
end
end
In short, get
, post
, put
, patch
, and delete
create example groups to describe actions to access API resources. Inside each example group:
- the description is automatically generated from the resource name and the action;
- the route, the action and any other optional argument are passed through using RSpec’s metadata;
- the method
respond_with
ofRSpecApi::Requests
is available, which is detailed hereafter.
respond_with
Coming soon…
has_attribute
Coming soon…
accept
Coming soon…
host
, adapter
Coming soon…
authorize_with
Coming soon…
throttle
Coming soon…