europeana-api 0.5.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +4 -2
  4. data/Gemfile +1 -8
  5. data/README.md +103 -21
  6. data/Rakefile +2 -1
  7. data/bin/console +21 -0
  8. data/europeana-api.gemspec +12 -1
  9. data/lib/europeana/api.rb +44 -68
  10. data/lib/europeana/api/annotation.rb +20 -0
  11. data/lib/europeana/api/client.rb +51 -0
  12. data/lib/europeana/api/entity.rb +16 -0
  13. data/lib/europeana/api/errors.rb +25 -41
  14. data/lib/europeana/api/faraday_middleware.rb +26 -0
  15. data/lib/europeana/api/faraday_middleware/request/authenticated_request.rb +25 -0
  16. data/lib/europeana/api/faraday_middleware/request/parameter_repetition.rb +25 -0
  17. data/lib/europeana/api/faraday_middleware/response/handle_text.rb +19 -0
  18. data/lib/europeana/api/faraday_middleware/response/parse_json_to_various.rb +52 -0
  19. data/lib/europeana/api/logger.rb +10 -0
  20. data/lib/europeana/api/queue.rb +47 -0
  21. data/lib/europeana/api/record.rb +29 -83
  22. data/lib/europeana/api/request.rb +77 -38
  23. data/lib/europeana/api/resource.rb +30 -0
  24. data/lib/europeana/api/response.rb +47 -0
  25. data/lib/europeana/api/version.rb +2 -1
  26. data/spec/europeana/api/annotation_spec.rb +77 -0
  27. data/spec/europeana/api/client_spec.rb +46 -0
  28. data/spec/europeana/api/entity_spec.rb +6 -0
  29. data/spec/europeana/api/faraday_middleware/request/authenticated_request_spec.rb +22 -0
  30. data/spec/europeana/api/queue_spec.rb +4 -0
  31. data/spec/europeana/api/record_spec.rb +54 -104
  32. data/spec/europeana/api/request_spec.rb +3 -0
  33. data/spec/europeana/api/resource_spec.rb +47 -0
  34. data/spec/europeana/api/response_spec.rb +10 -0
  35. data/spec/europeana/api_spec.rb +34 -84
  36. data/spec/spec_helper.rb +8 -0
  37. data/spec/support/shared_examples/resource_endpoint.rb +11 -0
  38. metadata +158 -34
  39. data/lib/europeana/api/record/hierarchy.rb +0 -48
  40. data/lib/europeana/api/record/hierarchy/ancestor_self_siblings.rb +0 -12
  41. data/lib/europeana/api/record/hierarchy/base.rb +0 -30
  42. data/lib/europeana/api/record/hierarchy/children.rb +0 -12
  43. data/lib/europeana/api/record/hierarchy/following_siblings.rb +0 -12
  44. data/lib/europeana/api/record/hierarchy/parent.rb +0 -12
  45. data/lib/europeana/api/record/hierarchy/preceding_siblings.rb +0 -15
  46. data/lib/europeana/api/record/hierarchy/self.rb +0 -12
  47. data/lib/europeana/api/requestable.rb +0 -118
  48. data/lib/europeana/api/search.rb +0 -64
  49. data/lib/europeana/api/search/fields.rb +0 -112
  50. data/spec/europeana/api/errors_spec.rb +0 -23
  51. data/spec/europeana/api/record/hierarchy_spec.rb +0 -15
  52. data/spec/europeana/api/search_spec.rb +0 -97
  53. data/spec/support/shared_examples/api_request.rb +0 -65
  54. data/spec/support/shared_examples/record_request.rb +0 -26
  55. data/spec/support/shared_examples/search_request.rb +0 -42
  56. data/spec/support/webmock.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 330985d53a6b1fb63021e3144d271c09b518deab
4
- data.tar.gz: 7d8c128ff306ba05a4f7a2a4e041c08fbce564b3
3
+ metadata.gz: a0b2c092e5307dddee16a30424d9f095d1881006
4
+ data.tar.gz: 9e55b99b93b151cf461c3ddf297329c163a7a3df
5
5
  SHA512:
6
- metadata.gz: 66111e036999c9cabcbd0ce2bbccccf507cccca8ca6d963c8ca68deeb66d7af01588be958c7fc984aad2a88c56538e95ca6e5301562adb236d229b1517c7a393
7
- data.tar.gz: 2d243b1d9e517e5b95a11d28e7853092421005541de037dfa824bc4b215113694d11e1e83cbfb88f2eb19fa9cae6f325646db3433f489b8c5faee1c216f2d3ec
6
+ metadata.gz: 57332276a79ed9680b91d31ed8439c67adef397fea3377062eb48797118796722d40e5506dd5fc829e13ea5e375ad81b0460495d1c8c125f3b0d1659756b003f
7
+ data.tar.gz: bfa182f373f3df742b5db95b3bb14ed9014b0c8ea99545e69ae5c37e1f52a02a9ef14c1104bd76f42e74185ef69a2f96e51cb174dfc74030335828b821eb43ee
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ /.ruby-version
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
@@ -15,3 +16,5 @@ spec/reports
15
16
  test/tmp
16
17
  test/version_tmp
17
18
  tmp
19
+ /.env
20
+ /.env.*
@@ -1,12 +1,14 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- - 2.1.7
5
3
  - 2.2.2
6
4
  - 2.2.3
7
5
  - 2.3.1
6
+ - 2.3.3
7
+ - 2.4.0
8
8
  notifications:
9
9
  email: false
10
10
  sudo: false
11
11
  cache:
12
12
  bundler: true
13
+ before_install:
14
+ - gem update --system
data/Gemfile CHANGED
@@ -1,12 +1,5 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in europeana.gemspec
4
5
  gemspec
5
-
6
- group :test do
7
- gem 'coveralls', require: false
8
- end
9
-
10
- group :test, :develop do
11
- gem 'rubocop', '0.39.0', require: false # only update when Hound does
12
- end
data/README.md CHANGED
@@ -1,15 +1,13 @@
1
- # Europeana
1
+ # Europeana API
2
2
 
3
- [![Build Status](https://travis-ci.org/europeana/europeana-api-client-ruby.svg?branch=master)](https://travis-ci.org/europeana/europeana-api-client-ruby) [![Coverage Status](https://coveralls.io/repos/europeana/europeana-api-client-ruby/badge.svg?branch=master&service=github)](https://coveralls.io/github/europeana/europeana-api-client-ruby?branch=master) [![security](https://hakiri.io/github/europeana/europeana-api-client-ruby/master.svg)](https://hakiri.io/github/europeana/europeana-api-client-ruby/master) [![Dependency Status](https://gemnasium.com/europeana/europeana-api-client-ruby.svg)](https://gemnasium.com/europeana/europeana-api-client-ruby)
3
+ [![Build Status](https://travis-ci.org/europeana/europeana-api-client-ruby.svg?branch=develop)](https://travis-ci.org/europeana/europeana-api-client-ruby) [![Coverage Status](https://coveralls.io/repos/europeana/europeana-api-client-ruby/badge.svg?branch=develop&service=github)](https://coveralls.io/github/europeana/europeana-api-client-ruby?branch=develop) [![security](https://hakiri.io/github/europeana/europeana-api-client-ruby/develop.svg)](https://hakiri.io/github/europeana/europeana-api-client-ruby/develop) [![Dependency Status](https://gemnasium.com/europeana/europeana-api-client-ruby.svg)](https://gemnasium.com/europeana/europeana-api-client-ruby)
4
4
 
5
5
  Ruby client library for the search and retrieval of records from the [Europeana
6
6
  REST API](http://labs.europeana.eu/api/introduction/).
7
7
 
8
- ## License
9
-
10
- Licensed under the EUPL V.1.1.
8
+ ## Requirements
11
9
 
12
- For full details, see [LICENSE.md](LICENSE.md).
10
+ * Ruby >= 2.2.2
13
11
 
14
12
  ## Installation
15
13
 
@@ -21,19 +19,21 @@ gem 'europeana-api'
21
19
 
22
20
  And then execute:
23
21
 
24
- $ bundle
22
+ ```
23
+ bundle
24
+ ```
25
25
 
26
26
  Or install it yourself as:
27
27
 
28
- $ gem install europeana-api
28
+ ```
29
+ gem install europeana-api
30
+ ```
29
31
 
30
32
  ## Usage
31
33
 
32
34
  ### Authentication
33
35
 
34
- Authentication is *required* for all requests to the Europeana API.
35
-
36
- Only Basic Authentication (by API key) is supported.
36
+ Authentication by API key is *required* for all requests to the Europeana API.
37
37
 
38
38
  Sign up for an API key at: http://labs.europeana.eu/api/registration/
39
39
 
@@ -41,26 +41,108 @@ Configure your application with the API key:
41
41
 
42
42
  ```ruby
43
43
  require 'europeana/api'
44
- Europeana::API.api_key = 'xyz'
44
+ Europeana::API.key = 'xyz'
45
+ ```
46
+
47
+ ### Response format
48
+
49
+ Responses from the API methods described below will by default be hashes with
50
+ indifferent access, i.e. values can be retrieved by string or symbol keys.
51
+
52
+ To have API methods return objects instead:
53
+ ```ruby
54
+ Europeana::API.configure do |config|
55
+ config.parse_json_to = OpenStruct
56
+ end
45
57
  ```
46
58
 
47
- ### Search
59
+ ### Records
60
+
61
+ #### Search
48
62
 
49
63
  ```ruby
50
- search = Europeana::API.search(query: '"first world war"') # => { "success" => true, "items" => [ ... ], "totalResults" => 1234, ... }
51
- search['items'] # => [ item1, item2, ... ]
52
- search['totalResults'] # => 1234
64
+ search = Europeana::API.record.search(query: '"first world war"')
65
+ search[:items] # => [ item1, item2, ... ]
66
+ search[:totalResults] # => 81530
53
67
  ```
54
68
 
55
- See http://labs.europeana.eu/api/search/ for details of the data returned in
56
- the search response.
69
+ See http://labs.europeana.eu/api/search/ for details of the available request
70
+ parameters, and of the data returned in the search response.
57
71
 
58
- ### Record
72
+ #### Fetch
59
73
 
60
74
  ```ruby
61
- record = Europeana::API.record('/abc/1234') # => { "success" => true, "object" => { ... }, ... }
62
- record['object'] # => { "title" => "...", "proxies" => [ ... ], "aggregations" => [ ... ], ... }
75
+ record = Europeana::API.record.fetch(id: '/92070/BibliographicResource_1000126223918')
76
+ record[:object][:title] # => ["Panorama des Schafberges in Ober-Österreich. Blatt 1"]
77
+ record[:object][:proxies].first[:dcCreator][:def] # => ["Simony, Friedrich"]
63
78
  ```
64
79
 
65
80
  See http://labs.europeana.eu/api/record/ for details of the data returned in
66
81
  the record response.
82
+
83
+ #### Hierarchies
84
+
85
+ ```ruby
86
+ hierarchy = Europeana::API.record.parent(id: '/2048604/data_item_onb_abo__2BZ17084070X')
87
+ hierarchy[:parent][:id] # => "/2048604/data_item_onb_abo_AC10352829"
88
+ ```
89
+
90
+ Methods available for hierarchy retrieval:
91
+ ```ruby
92
+ Europeana::API.record.self
93
+ Europeana::API.record.parent
94
+ Europeana::API.record.children
95
+ Europeana::API.record.preceding_siblings
96
+ Europeana::API.record.following_siblings
97
+ Europeana::API.record.ancestor_self_siblings
98
+ ```
99
+
100
+ See http://labs.europeana.eu/api/hierarchical-records for details of the various
101
+ hierarchy methods and their responses.
102
+
103
+ ### Annotations
104
+
105
+ See http://labs.europeana.eu/api/annotations-methods for details of the responses
106
+ received from the Annotations API methods.
107
+
108
+ #### Search
109
+
110
+ ```ruby
111
+ search = Europeana::API.annotation.search(query: 'music')
112
+ search[:items].first # => "http://data.europeana.eu/annotation/collections/8"
113
+ ```
114
+
115
+ #### Fetch
116
+
117
+ ```ruby
118
+ annotation = Europeana::API.annotation.fetch(provider: 'collections', id: 8)
119
+ annotation[:body] # => "Sheet music"
120
+ ```
121
+
122
+ #### Create
123
+
124
+ ```ruby
125
+ body = { bodyValue: 'Trombones', motivation: 'tagging', target: 'http://data.europeana.eu/item/09102/_UEDIN_214' }
126
+ annotation = Europeana::API.annotation.create(userToken: 'secret-token', body: body.to_json)
127
+ annotation[:id] # => "http://www.europeana.eu/api/annotations/myname/1234"
128
+ ```
129
+
130
+ #### Update
131
+
132
+ ```ruby
133
+ body = { bodyValue: 'Trombones', motivation: 'tagging' }
134
+ annotation = Europeana::API.annotation.update(provider: 'myname', id: '1234', userToken: 'secret-token', body: body.to_json)
135
+ annotation[:body][:value] # => "Trombones"
136
+ ```
137
+
138
+ #### Delete
139
+
140
+ ```ruby
141
+ Europeana::API.annotation.delete(provider: 'myname', id: '1234', userToken: 'secret-token') # => ""
142
+ ```
143
+
144
+ ## License
145
+
146
+ Licensed under the EUPL V.1.1.
147
+
148
+ For full details, see [LICENSE.md](LICENSE.md).
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
+ # frozen_string_literal: true
1
2
  require 'bundler/gem_tasks'
2
3
  require 'rspec/core/rake_task'
3
- task :default => :spec
4
+ task default: :spec
4
5
  RSpec::Core::RakeTask.new
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'dotenv'
5
+ Dotenv.load
6
+
7
+ require 'bundler/setup'
8
+ require 'europeana/api'
9
+
10
+ # You can add fixtures and/or initialization code here to make experimenting
11
+ # with your gem easier. You can also use a different console, if you like.
12
+
13
+ # (If you use this, don't forget to add pry to your Gemfile!)
14
+ # require 'pry'
15
+ # Pry.start
16
+
17
+ Europeana::API.key = ENV['EUROPEANA_API_KEY']
18
+ Europeana::API.url = ENV['EUROPEANA_API_URL'] if ENV['EUROPEANA_API_URL']
19
+
20
+ require 'irb'
21
+ IRB.start
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'europeana/api/version'
@@ -20,11 +21,21 @@ Gem::Specification.new do |spec|
20
21
 
21
22
  spec.required_ruby_version = '>= 2.0.0'
22
23
 
23
- spec.add_dependency 'activesupport', '>= 3.0', '< 5'
24
+ spec.add_dependency 'activesupport', '>= 4.2', '< 6.0'
25
+ # Locked to < v0.12.2 due to incompatibility with v0.12.2
26
+ # TODO: resolve incompatibility and unlock
27
+ spec.add_dependency 'faraday', '~> 0.9', '< 0.12.2'
28
+ spec.add_dependency 'faraday_middleware'
24
29
  spec.add_dependency 'multi_json', '~> 1.0'
30
+ spec.add_dependency 'rack', '> 1.6.2'
31
+ spec.add_dependency 'typhoeus', '~> 1.1'
25
32
 
26
33
  spec.add_development_dependency 'bundler', '~> 1.3'
34
+ spec.add_development_dependency 'coveralls'
35
+ spec.add_development_dependency 'dotenv'
27
36
  spec.add_development_dependency 'rake'
28
37
  spec.add_development_dependency 'rspec', '~> 3.0'
38
+ spec.add_development_dependency 'rubocop', '0.39.0' # only update when Hound does
39
+ spec.add_development_dependency 'shoulda-matchers', '~> 3.1'
29
40
  spec.add_development_dependency 'webmock', '~> 1.18.0'
30
41
  end
@@ -1,112 +1,88 @@
1
- require 'active_support/cache'
2
- require 'active_support/core_ext/object'
1
+ # frozen_string_literal: true
2
+ require 'active_support/concern'
3
+ require 'active_support/core_ext/class/attribute'
3
4
  require 'active_support/core_ext/hash/indifferent_access'
4
5
  require 'active_support/core_ext/hash/slice'
6
+ require 'active_support/core_ext/module/delegation'
7
+ require 'active_support/core_ext/object'
5
8
  require 'active_support/hash_with_indifferent_access'
6
9
  require 'active_support/inflector/methods'
10
+ require 'active_support/json'
7
11
  require 'europeana/api/version'
12
+ require 'europeana/api/logger'
8
13
  require 'logger'
9
14
  require 'uri'
10
15
 
11
16
  module Europeana
12
17
  ##
13
- # Europeana REST API client
18
+ # Interface to Europeana's RESTful API(s)
14
19
  module API
20
+ autoload :Annotation, 'europeana/api/annotation'
21
+ autoload :Client, 'europeana/api/client'
22
+ autoload :Entity, 'europeana/api/entity'
15
23
  autoload :Errors, 'europeana/api/errors'
24
+ autoload :FaradayMiddleware, 'europeana/api/faraday_middleware'
25
+ autoload :Queue, 'europeana/api/queue'
16
26
  autoload :Record, 'europeana/api/record'
17
27
  autoload :Request, 'europeana/api/request'
18
- autoload :Requestable, 'europeana/api/requestable'
19
- autoload :Search, 'europeana/api/search'
28
+ autoload :Resource, 'europeana/api/resource'
29
+ autoload :Response, 'europeana/api/response'
30
+
31
+ @url = 'https://www.europeana.eu/api'
20
32
 
21
33
  class << self
22
34
  ##
23
35
  # The Europeana API key, required for authentication
24
36
  #
25
37
  # @return [String]
26
- attr_accessor :api_key
38
+ attr_accessor :key
27
39
 
28
40
  ##
29
41
  # The API's base URL
30
42
  #
31
43
  # @return [String]
32
44
  attr_accessor :url
33
-
34
- ##
35
- # The maximum number of retries permitted
36
- #
37
- # Retries occur when a network request to the API fails. The default is 5
38
- # retries before giving up.
39
- #
40
- # @return [Integer]
41
- attr_accessor :max_retries
42
-
43
- ##
44
- # The number of seconds to wait between retries
45
- #
46
- # The default is 10 seconds.
47
- #
48
- # @return [Integer]
49
- attr_accessor :retry_delay
50
45
 
51
46
  # @return [Logger]
52
47
  attr_writer :logger
53
48
 
54
- attr_accessor :cache_store
49
+ def configuration
50
+ @configuration ||= Configuration.new
51
+ end
55
52
 
56
- attr_accessor :cache_expires_in
53
+ def logger
54
+ @logger ||= defined?(Rails) && Rails.logger ? Rails.logger : Logger.new(STDOUT)
55
+ end
57
56
 
58
- ##
59
- # Sets configuration values to their defaults
60
- def defaults!
61
- self.url = 'https://www.europeana.eu/api/v2'
62
- self.max_retries = 5
63
- self.retry_delay = 10
64
- self.cache_store = ActiveSupport::Cache::NullStore.new
65
- self.cache_expires_in = 24.hours
57
+ def configure
58
+ yield(configuration)
66
59
  end
67
60
 
68
- ##
69
- # Sends a Search request to the Europeana API
70
- #
71
- # Equivalent to:
72
- # search = Europeana::API::Search.new(params)
73
- # search.execute
74
- #
75
- # @param [Hash] params Query parameters
76
- # @return [Hash] search response
77
- # @see Europeana::API::Search#execute
78
- def search(params = {})
79
- Search.new(params).execute
61
+ def in_parallel(&block)
62
+ client = Client.new
63
+ yield client.queue
64
+ client.queue.run
80
65
  end
81
66
 
82
- ##
83
- # Sends a Record request to the Europeana API
84
- #
85
- # Equivalent to:
86
- # record = Europeana::API::Record.new(record_id, params)
87
- # record.get(options)
88
- #
89
- # @param [String] Record ID
90
- # @param [Hash] params Query parameters
91
- # @param [Hash] options (see Europeana::API::Record#get)
92
- # @return [Hash] search response
93
- # @see Europeana::API::Record#get
94
- def record(record_id, params = {}, options = {})
95
- Record.new(record_id, params).get(options)
67
+ def annotation
68
+ Annotation
96
69
  end
97
70
 
98
- def logger
99
- return @logger unless @logger.nil?
71
+ def record
72
+ Record
73
+ end
100
74
 
101
- @logger = case
102
- when defined?(Rails) && Rails.logger
103
- Rails.logger
104
- else
105
- Logger.new(STDOUT)
106
- end
75
+ def entity
76
+ Entity
107
77
  end
108
78
  end
109
79
 
110
- self.defaults!
80
+ class Configuration
81
+ attr_accessor :parse_json_to
82
+
83
+ def initialize
84
+ @parse_json_to = Hash
85
+ end
86
+ end
111
87
  end
112
88
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Europeana
3
+ module API
4
+ ##
5
+ # An annotation of a Europeana object
6
+ #
7
+ # @see http://labs.europeana.eu/api/annotations
8
+ class Annotation
9
+ include Resource
10
+
11
+ has_api_endpoint :search, method: :get, path: '/annotations/search'
12
+ has_api_endpoint :fetch, method: :get, path: '/annotations/%{provider}/%{id}'
13
+ has_api_endpoint :create, method: :post, path: '/annotations/',
14
+ headers: { 'Content-Type' => 'application/ld+json' }
15
+ has_api_endpoint :update, method: :put, path: '/annotations/%{provider}/%{id}',
16
+ headers: { 'Content-Type' => 'application/ld+json' }
17
+ has_api_endpoint :delete, method: :delete, path: '/annotations/%{provider}/%{id}'
18
+ end
19
+ end
20
+ end