Skip to content

Commit

Permalink
added versioning to API response
Browse files Browse the repository at this point in the history
  • Loading branch information
alinvetian committed Oct 23, 2024
1 parent 323db3c commit 5b68c51
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
3 changes: 3 additions & 0 deletions app/controllers/api_application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

# class ApplicationController < ActionController::Base
class ApiApplicationController < StashEngine::ApplicationController
include StashApi::Versioning

layout 'layouts/stash_engine/application'

before_action :log_request
before_action :set_response_version_header
before_action :check_requested_version
skip_before_action :verify_authenticity_token

DEFAULT_PAGE_SIZE = 20
Expand Down
34 changes: 34 additions & 0 deletions app/controllers/stash_api/versioning.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module StashApi
module Versioning
extend ActiveSupport::Concern

private

def set_response_version_header
response.headers['X-API-Version'] = api_version
return if api_version == current_version

response.headers['X-API-Deprecation'] = 'true'
end

def check_requested_version
return if !requested_version || requested_version == current_version

render json: { error: "Unsupported API version: #{requested_version}, latest version is: #{current_version}" }, status: 400
end

def current_version
'2.1.0'
end

def api_version
return requested_version if requested_version

request.path.include?('/api/v2') ? '2.1.0' : '1.0.0'
end

def requested_version
@requested_version ||= request.headers['X-API-Version']
end
end
end
21 changes: 21 additions & 0 deletions documentation/apis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,24 @@ Dryad maintains a variety of reports regarding its content.
- Reports that are automatically generated on a regular basis are available at `https://datadryad.org/api/v2/reports`
- Reports that are generated less frequently are available through our [Data about Dryad](https://github.com/datadryad/dryad-data/) repository


API Versioning
============

The Dryad API uses [Semantic Versioning](https://semver.org/) to track changes to the API.

The current version of our API is `2.1.0`. This is also the only supported API versions, at the moment.

In order to use the latest API version, you can:
- Use `https://datadryad.org/api/v2/` as the base URL for all API requests.
- You can also send send the `X-API-Version: 2.1.0`

We added 2 new response headers:
- The `X-API-Version` header to allow clients to specify the version of the API they are using.
- The `X-API-Deprecation` header to notify clients if the version they are using is deprecated and will be removed in the future.

In case a bad version number is used, the API will respond with:
- `400` error status.
- `{ "error": "Unsupported API version: {requested-version}, latest version is: 2.1.0" }` in the response body.
- The `X-API-Version` header set to the version of the API you requested.
- The `X-API-Deprecation` header set `true`. This header will not be returned in case the version you are using is not deprecated.
48 changes: 48 additions & 0 deletions spec/requests/api_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,53 @@ module StashApi
expect(hsh['_links']['stash:datasets']['href']).to eql('/api/v2/datasets')
end
end

describe '#versioning' do
before { post '/api/v2/test', headers: request_headers }

context 'with no X-API-Version header' do
context 'with current API version' do
let(:request_headers) { default_authenticated_headers }

it 'is successful and has correct response headers' do
expect(response).to be_successful
expect(response.headers['X-API-Version']).to eql('2.1.0')
expect(response.headers['X-API-deprecation']).to be_nil
end
end
end

context 'with X-API-Version header' do
context 'with current API version' do
let(:request_headers) { default_authenticated_headers.merge('X-API-Version' => '2.1.0') }

it 'is successful and has correct response headers' do
expect(response).to be_successful
expect(response.headers['X-API-Version']).to eql('2.1.0')
expect(response.headers['X-API-Deprecation']).to be_nil
end
end

context 'with old API version' do
let(:request_headers) { default_authenticated_headers.merge('X-API-Version' => '1.0.0') }

it 'returns 400 and has correct response headers' do
expect(response.status).to eql(400)
expect(response.headers['X-API-Version']).to eql('1.0.0')
expect(response.headers['X-API-Deprecation']).to be_truthy
end
end

context 'with bad API version' do
let(:request_headers) { default_authenticated_headers.merge('X-API-Version' => 'bad version') }

it 'returns 400 and has correct response headers' do
expect(response.status).to eql(400)
expect(response.headers['X-API-Version']).to eql('bad version')
expect(response.headers['X-API-Deprecation']).to be_truthy
end
end
end
end
end
end

0 comments on commit 5b68c51

Please sign in to comment.