Commit 195b2b4b authored by Bruno Nocera Zanette's avatar Bruno Nocera Zanette

Merge branch 'add-report-endpoints' into 'master'

Add Report Endpoints



See merge request !11
parents 4e797c1c bd817c94
Pipeline #7150 passed with stage
in 22 seconds
......@@ -10,4 +10,4 @@ gem 'activesupport'
group :development, :spec do
gem 'minitest', '~> 5.8.3'
gem 'rspec'
end
\ No newline at end of file
end
......@@ -16,6 +16,63 @@ Or install it yourself as:
$ gem install dspace_rest_client
## Resources
### Item's resources
* action :all, 'GET /rest/items' (query_keys :expand, :limit, :offset)
* action :find, 'GET /rest/items/:id' (query_keys :expand)
* action :find_by_metadata, 'POST /rest/items/find-by-metadata-field'
* action :metadata, 'GET /rest/items/:id/metadata'
* action :bitstreams, 'GET /rest/items/:id/bitstreams' (query_keys :expand, :limit, :offset)
* action :delete, 'DELETE /rest/items/:id'
* action :clear_metadata, 'DELETE /rest/items/:id/metadata'
* action :delete_bitstream, 'DELETE /rest/items/:id/bitstreams/:bitstream_id'
* action :add_metadata, 'POST /rest/items/:id/metadata'
* action :add_bitstream, 'POST /rest/items/:id/bitstreams' (query_keys :name, :description, :bundle_name)
* action :update_metadata, 'PUT /rest/items/:id/metadata'
### Collection's resources
* action :all, 'GET /rest/collections' (query_keys :expand, :limit, :offset)
* action :find, 'GET /rest/collections/:id' (query_keys :expand)
* action :update, 'PUT /rest/collections/:id'
* action :delete, 'DELETE /rest/collections/:id'
* action :delete_item, 'DELETE /rest/collections/:id/items/:item_id'
* action :items, 'GET /rest/collections/:id/items' (query_keys :expand, :limit, :offset)
* action :create_item, 'POST /rest/collections/:id/items'
### Community's resources
* action :all, 'GET /rest/communities' (query_keys :expand, :limit, :offset)
* action :top_communities, 'GET /rest/communities/top-communities' (query_keys :expand, :limit, :offset)
* action :find, 'GET /rest/communities/:id' (query_keys :expand)
* action :collections, 'GET /rest/communities/:id/collections' (query_keys :expand, :limit, :offset)
* action :sub_communities, 'GET /rest/communities/:id/communities' (query_keys :expand, :limit, :offset)
* action :create, 'POST /rest/communities'
* action :create_subcommunity, 'POST /rest/communities/:id/communities'
* action :create_collection, 'POST /rest/communities/:id/collections'
* action :update, 'PUT /rest/communities/:id'
* action :delete, 'DELETE /rest/communities/:id'
* action :delete_collection, 'DELETE /rest/communities/:id/collections/:collection_id'
* action :delete_subcommunity, 'DELETE /rest/communities/:id/communities/:subcommunity_id'
### Bitstream's resources
* action :all, 'GET /rest/bitstreams' (query_keys :expand, :limit, :offset)
* action :find, 'GET /rest/bitstreams/:id' (query_keys :expand)
* action :policy, 'GET /rest/bitstreams/:id/policy'
* action :retrieve, 'GET /rest/bitstreams/:id/retrieve'
* action :delete, 'DELETE /rest/bitstreams/:id'
* action :delete_policy, 'DELETE /rest/bitstreams/:id/policy/:policy_id'
* action :add_policy, 'POST /rest/bitstreams/:id/policy'
* action :update, 'PUT /rest/bitstreams/:id'}
* action :update_data, 'PUT /rest/bitstreams/:id/data' do
### Authentication's resources
* action :login, 'POST /rest/login'
* action :logout, 'POST /rest/logout'
### Status's resources
* action :test, 'GET /rest/test'
* action :status, 'GET /rest/status'
## Get started
Some requests requires user authentication.
......@@ -55,4 +112,4 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
## Contributing
Bug reports and pull requests are welcome. This project is intended to be a safe, welcoming space for collaboration.
\ No newline at end of file
Bug reports and pull requests are welcome. This project is intended to be a safe, welcoming space for collaboration.
......@@ -18,13 +18,13 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.require_paths = ['lib']
spec.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
spec.add_runtime_dependency 'resource_kit', '>= 0.1.4'
spec.add_runtime_dependency 'faraday', '~> 0.9.2'
spec.add_runtime_dependency 'net-http-persistent', '~> 2.9', '>= 2.9.4'
spec.add_runtime_dependency 'activesupport', '>= 4.2.0'
spec.add_runtime_dependency "json", '~> 1.8', '>= 1.8.3'
spec.add_runtime_dependency "resource_kit", "~> 0.1.4"
spec.add_runtime_dependency "faraday", "~> 0.9.2"
spec.add_runtime_dependency "net-http-persistent", '~> 2.9', '>= 2.9.4'
spec.add_runtime_dependency "activesupport", '>= 4.2.0'
spec.add_development_dependency 'bundler', '~> 1.10'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.4', '>= 3.4.0'
end
end
\ No newline at end of file
......@@ -5,6 +5,9 @@ require "faraday"
require "active_support/all"
require_relative "dspace/version"
require_relative "dspace/resources/report_resource"
require_relative "dspace/resources/hierarchy_resource"
require_relative "dspace/resources/schema_registry_resource"
require_relative "dspace/resources/community_resource"
require_relative "dspace/resources/collection_resource"
require_relative "dspace/resources/authentication_resource"
......@@ -14,17 +17,26 @@ require_relative "dspace/resources/item_resource"
require_relative "dspace/builders/hash_builder"
require_relative "dspace/builders/model_builder"
require_relative "dspace/builders/tempfile_builder"
require_relative "dspace/site"
require_relative "dspace/community"
require_relative "dspace/collection"
require_relative "dspace/item"
require_relative "dspace/metadata"
require_relative "dspace/schema"
require_relative "dspace/metadata_field"
require_relative "dspace/bitstream"
require_relative "dspace/policy"
require_relative "dspace/item_filter"
require_relative "dspace/report"
require_relative "dspace/client"
module Dspace
class NotAuthorizedError < StandardError; end
class NotFoundError < StandardError; end
class MethodNotAllowedError < StandardError; end
class UnsupportedMediaTypeError < StandardError; end
class ServerError < StandardError; end
class InvalidTokenError < StandardError; end
class InvalidCredentialsError < StandardError; end
......
......@@ -9,12 +9,12 @@ module Dspace
:parent_object, :retrieve_link, :check_sum,
:sequence_id, :policies
def initialize args
@id = args['id']
def initialize(args={})
@id = args['id'] || args['uuid']
@name = args['name']
@type = args['type']
@link = args['link']
@bundle_name = args['bundleName']
@bundle_name = args['bundleName'] || args['bundle_name']
@description = args['description']
@format = args['format']
@mime_type = args['mimeType']
......@@ -29,7 +29,7 @@ module Dspace
def to_h
{
id: @id,
uuid: @id,
name: @name,
type: @type,
link: @link,
......
......@@ -29,6 +29,24 @@ module Dspace
colls
end
def self.build_schemas(schemas=[])
return schemas unless schemas.is_a? Array
colls = []
schemas.each do |c|
colls << Dspace::Schema.new(c)
end
colls
end
def self.build_fields(fields=[])
return fields unless fields.is_a? Array
colls = []
fields.each do |c|
colls << Dspace::MetadataField.new(c)
end
colls
end
def self.build_bitstreams(bitstreams=[])
return bitstreams unless bitstreams.is_a? Array
colls = []
......@@ -56,6 +74,24 @@ module Dspace
colls
end
def self.build_reports(reports=[])
return reports unless reports.is_a? Array
colls = []
reports.each do |c|
colls << Dspace::Report.new(c)
end
colls
end
def self.build_item_filters(item_filters=[])
return item_filters unless item_filters.is_a? Array
colls = []
item_filters.each do |c|
colls << Dspace::ItemFilter.new(c)
end
colls
end
def self.models2hash(list)
if list.is_a? Array
list.map do |m|
......
......@@ -16,6 +16,7 @@ module Dspace
filename.gsub!(/^.*(\\|\/)/, '')
# Strip out the non-ascii character
filename.gsub!(/[^0-9A-Za-z.\-]/, '_')
filename
end
end
......
......@@ -2,7 +2,7 @@ module Dspace
class Client
DSPACE_API = 'https://demo.dspace.org'
attr_reader :access_token
attr_accessor :access_token
def initialize(options = {})
@access_token = options.with_indifferent_access[:access_token]
......@@ -12,6 +12,7 @@ module Dspace
def connection
Faraday.new(connection_options) do |req|
# req.response :logger
req.request :multipart
req.request :url_encoded
req.use(Faraday::Response::Logger, @logger) unless @logger.nil?
......@@ -26,7 +27,10 @@ module Dspace
collections: ::Dspace::Resources::CollectionResource,
communities: ::Dspace::Resources::CommunityResource,
status: ::Dspace::Resources::StatusResource,
authentication: ::Dspace::Resources::AuthenticationResource
authentication: ::Dspace::Resources::AuthenticationResource,
schema_registry: ::Dspace::Resources::SchemaRegistryResource,
hierarchy: ::Dspace::Resources::HierarchyResource,
report: ::Dspace::Resources::ReportResource
}
end
......@@ -42,36 +46,39 @@ module Dspace
resource(:status).test
end
def status
resource(:status).status
end
def login(email, password)
@access_token = resource(:authentication).login(email, password)
@access_token = resource(:authentication).login(email: email, password: password)
end
def logout
resource(:authentication).logout
@access_token = nil
(response = resource(:authentication).logout) && @access_token = nil
response
end
private
def resource(name)
if self.class.resources.keys.include?(name)
resources[name] ||= self.class.resources[name].new(connection: connection)
resources[name]
resources[name] = self.class.resources[name].new(connection: connection)
end
end
def connection_options
{
url: @dspace_api || DSPACE_API,
ssl: {
verify: false
},
headers: {
content_type: 'application/json',
accept: 'application/json',
'rest-dspace-token' => access_token.to_s,
user_agent: "dspace-rest-client #{Dspace::VERSION}"
}
url: @dspace_api || DSPACE_API,
ssl: {
verify: false
},
headers: {
content_type: 'application/json',
accept: 'application/json',
user_agent: "dspace-rest-client #{Dspace::VERSION}",
'Cookie' => @access_token.to_s
}
}
end
end
......
......@@ -9,18 +9,18 @@ module Dspace
:parent_community_list, :items,
:number_items, :expand
def initialize args
@id = args['id']
def initialize(args={})
@id = args['id'] || args['uuid']
@name = args['name']
@handle = args['handle']
@type = args['type']
@link = args['link']
@logo = args['logo']
@logo = Dspace::Bitstream.new(args['logo']) unless args['logo'].nil?
@license = args['license']
@copyright_text = args['copyrightText']
@introductory_text = args['introductoryText']
@short_description = args['shortDescription']
@sidebar_text = args['sidebarText']
@copyright_text = args['copyrightText'] || args['copyright_text']
@introductory_text = args['introductoryText'] || args['introductory_text']
@short_description = args['shortDescription'] || args['short_description']
@sidebar_text = args['sidebarText'] || args['sidebar_text']
@number_items = args['numberItems']
@expand = args['expand']
......@@ -31,14 +31,14 @@ module Dspace
def to_h
{
id: @id,
uuid: @id,
name: @name,
handle: @handle,
type: @type,
link: @link,
logo: @logo,
parentCommunity: @parent_community,
parentCommunitList: @parent_community_list,
parentCommunityList: @parent_community_list,
items: obj2hash(@items),
license: @license,
copyrightText: @copyright_text,
......@@ -51,4 +51,4 @@ module Dspace
end
end
end
\ No newline at end of file
end
......@@ -8,26 +8,35 @@ module Dspace
:count_items, :sub_communities, :collections, :expand
def initialize(args={})
@id = args['id']
@id = args['id'] || args['uuid']
@name = args['name']
@handle = args['handle']
@type = args['type']
@link = args['link']
@logo = args['logo']
@logo = Dspace::Bitstream.new(args['logo']) unless args['logo'].nil?
@parent_community = Dspace::Community.new(args['parentCommunity']) unless args['parentCommunity'].nil?
@copyright_text = args['copyrightText']
@introductory_text = args['introductoryText']
@short_description = args['shortDescription']
@sidebar_text = args['sidebarText']
@copyright_text = args['copyrightText'] || args['copyright_text']
@introductory_text = args['introductoryText'] || args['introductory_text']
@short_description = args['shortDescription'] || args['short_description']
@sidebar_text = args['sidebarText'] || args['sidebar_text']
@count_items = args['countItems']
@sub_communities = Dspace::Builders::ModelBuilder.build_communities(args['subcommunities']) unless args['subcommunities'].nil?
@collections = Dspace::Builders::ModelBuilder.build_collections(args['collections']) unless args['collections'].nil?
# subcommunities = All community endpoints
# community = Hierarchy endpoint
sub_communities = args['subcommunities'] || args['community']
@sub_communities = Dspace::Builders::ModelBuilder.build_communities(sub_communities) unless sub_communities.nil?
# collections = All community/collection endpoints
# collection = Hierarchy endpoint
collections = args['collections'] || args['collection']
@collections = Dspace::Builders::ModelBuilder.build_collections(collections) unless collections.nil?
@expand = args['expand']
end
def to_h
{
id: @id,
uuid: @id,
name: @name,
handle: @handle,
type: @type,
......@@ -48,7 +57,7 @@ module Dspace
private
def obj2hash(list)
Dspace::Builders::HashBuilder.models2hash list if list.is_a? Array
Dspace::Builders::ModelBuilder.models2hash list if list.is_a? Array
end
end
......
......@@ -8,8 +8,8 @@ module Dspace
:parent_collection_list, :parent_community_list, :bit_streams,
:expand, :metadata
def initialize args
@id = args['id']
def initialize(args={})
@id = args['id'] || args['uuid']
@name = args['name']
@handle = args['handle']
@type = args['type']
......@@ -22,12 +22,12 @@ module Dspace
@archived = args['archived']
@withdrawn = args['withdrawn']
@expand = args['expand']
@metadata = Dspace::Builders::ModelBuilder.build_metadatas(args['metadata'])
@metadata = Dspace::Builders::ModelBuilder.build_metadatas(args['metadata']) || []
end
def to_h
{
id: @id,
uuid: @id,
name: @name,
handle: @handle,
type: @type,
......
module Dspace
class ItemFilter
attr_reader :category, :filter_name, :title
def initialize(args={})
@category = args['category']
@filter_name = args['filter-name']
@title = args['title']
end
def to_h
{category: @category, 'filter-name': @filter_name, title: @title}
end
end
end
......@@ -2,7 +2,7 @@ module Dspace
class Metadata
attr_accessor :key, :value, :language
def initialize args
def initialize(args={})
@key = args['key']
@value = args['value']
@language = args['language'] || nil
......
module Dspace
class MetadataField
include Dspace::Builders::HashBuilder
attr_accessor :name, :element, :qualifier, :description
attr_reader :id, :parent_schema, :expand
def initialize(args={})
@id = args['fieldId']
@name = args['name']
@parent_schema = args['parentSchema'] || args['parent_schema']
@element = args['element']
@qualifier = args['qualifier']
@description = args['description']
@expand = args['expand']
end
def to_h
{
fieldId: @id,
name: @name,
parentSchema: @parent_schema,
element: @element,
qualifier: @qualifier,
description: @description,
expand: @expand
}
end
end
end
module Dspace
class Report
attr_reader :nickname, :url
def initialize(args={})
@nickname = args['nickname']
@url = args['url']
end
def to_h
{nickname: @nickname, url: @url}
end
end
end
......@@ -3,18 +3,26 @@ module Dspace
class AuthenticationResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :login, 'POST /rest/login' do
body { |email, password| JSON.generate({email: email, password: password}) }
handler(200, 201) { |response| access_token = response.body }
query_keys :email, :password
handler(200, 201) { |response| response['set-cookie'] }
end
action :logout, 'POST /rest/logout' do
body { |object| JSON.generate(object.to_h) }
handler(200, 201, 203, 204) { |response| true }
end
end
end
......
......@@ -3,12 +3,20 @@ module Dspace
class BitstreamResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :all, 'GET /rest/bitstreams' do
query_keys :expand, :limit, :offset
handler(200) do |response|
Dspace::Builders::ModelBuilder.build_items(JSON.parse(response.body))
Dspace::Builders::ModelBuilder.build_bitstreams(JSON.parse(response.body))
end
end
......@@ -48,7 +56,7 @@ module Dspace
end
action :update_data, 'PUT /rest/bitstreams/:id/data' do
body { |file| Base64.encode64(file.read) }
body { |file| file.read }
handler(200, 201) { |response| true }
end
end
......
......@@ -3,7 +3,15 @@ module Dspace
class CollectionResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :all, 'GET /rest/collections' do
query_keys :expand, :limit, :offset
......@@ -47,4 +55,4 @@ module Dspace
end
end
end
end
\ No newline at end of file
end
......@@ -3,7 +3,15 @@ module Dspace
class CommunityResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :all, 'GET /rest/communities' do
query_keys :expand, :limit, :offset
......@@ -42,17 +50,17 @@ module Dspace
action :create, 'POST /rest/communities' do
body { |object| JSON.generate(object.to_h) }
handler(200, 201) { |response| true }
handler(200, 201) { |response| Dspace::Community.new(JSON.parse(response.body)) }
end
action :create_subcommunity, 'POST /rest/communities/:id/communities' do
body { |object| JSON.generate(object.to_h) }
handler(200, 201) { |response| true }
handler(200, 201) { |response| Dspace::Community.new(JSON.parse(response.body)) }
end
action :create_collection, 'POST /rest/communities/:id/collections' do
body { |object| JSON.generate(object.to_h) }
handler(200, 201) { |response| true }
handler(200, 201) { |response| Dspace::Collection.new(JSON.parse(response.body)) }
end
action :update, 'PUT /rest/communities/:id' do
......@@ -75,4 +83,4 @@ module Dspace
end
end
end
end
\ No newline at end of file
end
module Dspace
module Resources
class HierarchyResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :all, 'GET /rest/hierarchy' do
handler(200) do |response|
Dspace::Site.new(JSON.parse(response.body))
end
end
end
end
end
end
......@@ -3,7 +3,15 @@ module Dspace
class ItemResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }
default_handler { |response| raise StandardError, "#{response.inspect}" }
action :all, 'GET /rest/items' do
query_keys :expand, :limit, :offset
......@@ -19,6 +27,13 @@ module Dspace
end
end
action :find_by_metadata, 'POST /rest/items/find-by-metadata-field' do
body { |object| JSON.generate(object.to_h) }
handler(200) do |response|
Dspace::Builders::ModelBuilder.build_items(JSON.parse(response.body))
end
end
action :metadata, 'GET /rest/items/:id/metadata' do
handler(200) do |response|
Dspace::Builders::ModelBuilder.build_metadatas(JSON.parse(response.body))
......@@ -56,7 +71,7 @@ module Dspace
end
action :update_metadata, 'PUT /rest/items/:id/metadata' do
body { |object| JSON.generate(object.to_h) }
body { |object| JSON.generate(Dspace::Builders::ModelBuilder.models2hash(object))}
handler(200, 201) { |response| true }
end
......
module Dspace
module Resources
class ReportResource < ResourceKit::Resource
resources do
default_handler(400) { raise InvalidTokenError, 'Invalid access token.' }
default_handler(403) { raise InvalidCredentialsError, 'Wrong Dspace credentials.' }
default_handler(401) { raise NotAuthorizedError, 'This request requires authentication' }
default_handler(404) { raise NotFoundError, 'The specified object doesn\'t exist' }
default_handler(405) { raise MethodNotAllowedError, 'Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML)' }
default_handler(415) { raise UnsupportedMediaTypeError, 'Missing "Content-Type: application/json" or "Content-Type: application/xml" request header' }
default_handler(500) { raise ServerError, 'Likely a SQLException, IOException, more details in the logs' }