nypl_platform_api_client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []