nypl_platform_api_client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1df8231c019f86e347ab7fa83b1f13db8aa1f02ef3488c1aa5eb055cbaacc63e
4
+ data.tar.gz: ecd9488ca99d6790e4e35362840861636f5b34a34aaf68a42f4cc963db090ef2
5
+ SHA512:
6
+ metadata.gz: 42b3a9a06976b667c9ac2dd80742d421adc0af0d65c133798bd19ebd602d728e742285e3c2c8e3f13bfce4cc76e1389f4c517a29aacb60384fa4b29362e08aff
7
+ data.tar.gz: f9c3acf9e5a9e2ff9bc8520049f83a027c5b6271668d60697f09eb4fb66af651ba0be0d481ce9495e59d81bba1196415bc73e18fe3eac2c14d45c33e7e408657
data/lib/errors.rb ADDED
@@ -0,0 +1,5 @@
1
+ class NyplPlatformApiClientError < StandardError
2
+ end
3
+
4
+ class NyplPlatformApiClientTokenError < NyplPlatformApiClientError
5
+ end
@@ -0,0 +1,148 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+
5
+ require_relative 'errors'
6
+
7
+ class NyplPlatformApiClient
8
+ def initialize(config = {})
9
+ @config = {
10
+ base_url: ENV['PLATFORM_API_BASE_URL'],
11
+ client_id: ENV['NYPL_OAUTH_ID'],
12
+ client_secret: ENV['NYPL_OAUTH_SECRET'],
13
+ oauth_url: ENV['NYPL_OAUTH_URL'],
14
+ log_level: 'info'
15
+ }.merge config
16
+
17
+ raise NyplPlatformApiClientError.new 'Missing config: neither config.base_url nor ENV.PLATFORM_API_BASE_URL are set' unless @config[:base_url]
18
+ raise NyplPlatformApiClientError.new 'Missing config: neither config.client_id nor ENV.NYPL_OAUTH_ID are set' unless @config[:client_id]
19
+ raise NyplPlatformApiClientError.new 'Missing config: neither config.client_secret nor ENV.NYPL_OAUTH_SECRET are set ' unless @config[:client_secret]
20
+ raise NyplPlatformApiClientError.new 'Missing config: neither config.oauth_url nor ENV.NYPL_OAUTH_URL are set ' unless @config[:oauth_url]
21
+ end
22
+
23
+ def get (path, options = {})
24
+ options = parse_http_options options
25
+
26
+ authenticate! if options[:authenticated]
27
+
28
+ uri = URI.parse("#{@config[:base_url]}#{path}")
29
+
30
+ logger.debug "NyplPlatformApiClient: Getting from platform api", { uri: uri }
31
+
32
+ begin
33
+ request = Net::HTTP::Get.new(uri)
34
+
35
+ # Add bearer token header
36
+ request["Authorization"] = "Bearer #{@access_token}" if options[:authenticated]
37
+
38
+ # Execute request:
39
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme === 'https') do |http|
40
+ http.request(request)
41
+ end
42
+ rescue Exception => e
43
+ raise NyplPlatformApiClientError.new(e), "Failed to GET #{path}: #{e.message}"
44
+ end
45
+
46
+ logger.debug "NyplPlatformApiClient: Got platform api response", { code: response.code, body: response.body }
47
+
48
+ parse_json_response response
49
+ end
50
+
51
+ def post (path, body, options = {})
52
+ options = parse_http_options options
53
+
54
+ # Default to POSTing JSON unless explicitly stated otherwise
55
+ options[:headers]['Content-Type'] = 'application/json' unless options[:headers]['Content-Type']
56
+
57
+ authenticate! if options[:authenticated]
58
+
59
+ uri = URI.parse("#{@config[:base_url]}#{path}")
60
+
61
+ http = Net::HTTP.new(uri.host, uri.port)
62
+ http.use_ssl = uri.scheme === 'https'
63
+
64
+ begin
65
+ request = Net::HTTP::Post.new(uri.path, 'Content-Type' => options[:headers]['Content-Type'])
66
+ request.body = body.to_json
67
+
68
+ logger.debug "NyplPlatformApiClient: Posting to platform api", { uri: uri, body: body }
69
+
70
+ # Add bearer token header
71
+ request['Authorization'] = "Bearer #{@access_token}" if options[:authenticated]
72
+
73
+ # Execute request:
74
+ response = http.request(request)
75
+ rescue Exception => e
76
+ raise NyplPlatformApiClientError.new(e), "Failed to POST to #{path}: #{e.message}"
77
+ end
78
+
79
+ logger.debug "NyplPlatformApiClient: Got platform api response", { code: response.code, body: response.body }
80
+
81
+ parse_json_response response
82
+ end
83
+
84
+ private
85
+
86
+ def parse_http_options (_options)
87
+ options = {
88
+ authenticated: true
89
+ }.merge _options
90
+
91
+ options[:headers] = {
92
+ }.merge(_options[:headers] || {})
93
+ .transform_keys(&:to_s)
94
+
95
+ options
96
+ end
97
+
98
+ def parse_json_response (response)
99
+ # Among NYPL services, these are the only non-error statuses with useful JSON payloads:
100
+ if ['200', '404'].include? response.code
101
+ begin
102
+ JSON.parse(response.body)
103
+ rescue => e
104
+ raise NyplPlatformApiClientError, "Error parsing response (#{response.code}): #{response.body}"
105
+ end
106
+ elsif response.code == "401"
107
+ # Likely an expired access-token; Wipe it for next run
108
+ @access_token = nil
109
+ raise NyplPlatformApiClientTokenError.new("Got a 401: #{response.body}")
110
+ else
111
+ raise NyplPlatformApiClientError, "Error interpretting response (#{response.code}): #{response.body}"
112
+ end
113
+ end
114
+
115
+ # Authorizes the request.
116
+ def authenticate!
117
+ # NOOP if we've already authenticated
118
+ return nil if ! @access_token.nil?
119
+
120
+ logger.debug "NyplPlatformApiClient: Authenticating with client_id #{@config[:client_id]}"
121
+
122
+ uri = URI.parse("#{@config[:oauth_url]}oauth/token")
123
+ request = Net::HTTP::Post.new(uri)
124
+ request.basic_auth(@config[:client_id], @config[:client_secret])
125
+ request.set_form_data(
126
+ "grant_type" => "client_credentials"
127
+ )
128
+
129
+ req_options = {
130
+ use_ssl: uri.scheme == "https",
131
+ request_timeout: 500
132
+ }
133
+
134
+ response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
135
+ http.request(request)
136
+ end
137
+
138
+ if response.code == '200'
139
+ @access_token = JSON.parse(response.body)["access_token"]
140
+ else
141
+ nil
142
+ end
143
+ end
144
+
145
+ def logger
146
+ @logger ||= NyplLogFormatter.new(STDOUT, level: @config[:log_level])
147
+ end
148
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nypl_platform_api_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - nonword
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Client for querying NYPL's internal Platform API
14
+ email: paulbeaudoin@nypl.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/errors.rb
20
+ - lib/nypl_platform_api_client.rb
21
+ homepage: https://github.com/NYPL/ruby_nypl_platform_nypl_client
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.7.3
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: NYPL Platform API client
45
+ test_files: []