solvebio 1.6.1 → 1.7.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.
- data/.bumpversion.cfg +6 -0
- data/.gitignore +5 -4
- data/.travis.yml +1 -1
- data/Gemfile +3 -0
- data/README.md +34 -34
- data/Rakefile +1 -18
- data/bin/solvebio.rb +14 -16
- data/installer +64 -0
- data/lib/solvebio.rb +50 -11
- data/lib/solvebio/acccount.rb +4 -0
- data/lib/solvebio/annotation.rb +11 -0
- data/lib/solvebio/api_operations.rb +147 -0
- data/lib/solvebio/api_resource.rb +32 -0
- data/lib/solvebio/cli.rb +75 -0
- data/lib/solvebio/cli/auth.rb +106 -0
- data/lib/solvebio/cli/credentials.rb +54 -0
- data/lib/{cli → solvebio/cli}/irb.rb +0 -23
- data/lib/solvebio/cli/irbrc.rb +48 -0
- data/lib/solvebio/cli/tutorial.rb +12 -0
- data/lib/solvebio/client.rb +149 -0
- data/lib/solvebio/dataset.rb +60 -0
- data/lib/solvebio/dataset_field.rb +12 -0
- data/lib/solvebio/depository.rb +38 -0
- data/lib/solvebio/depository_version.rb +40 -0
- data/lib/solvebio/errors.rb +64 -0
- data/lib/solvebio/filter.rb +315 -0
- data/lib/solvebio/list_object.rb +73 -0
- data/lib/solvebio/locale.rb +43 -0
- data/lib/solvebio/query.rb +341 -0
- data/lib/solvebio/sample.rb +54 -0
- data/lib/solvebio/singleton_api_resource.rb +25 -0
- data/lib/solvebio/solve_object.rb +164 -0
- data/lib/solvebio/tabulate.rb +589 -0
- data/lib/solvebio/user.rb +4 -0
- data/lib/solvebio/util.rb +59 -0
- data/lib/solvebio/version.rb +3 -0
- data/solvebio.gemspec +10 -18
- data/test/helper.rb +6 -2
- data/test/solvebio/data/.gitignore +1 -0
- data/test/solvebio/data/.netrc +6 -0
- data/test/{data → solvebio/data}/netrc-save +0 -0
- data/test/solvebio/data/sample.vcf.gz +0 -0
- data/test/solvebio/data/test_creds +3 -0
- data/test/solvebio/test_annotation.rb +45 -0
- data/test/solvebio/test_client.rb +29 -0
- data/test/solvebio/test_conversion.rb +14 -0
- data/test/solvebio/test_credentials.rb +67 -0
- data/test/solvebio/test_dataset.rb +52 -0
- data/test/solvebio/test_depository.rb +24 -0
- data/test/solvebio/test_depositoryversion.rb +22 -0
- data/test/solvebio/test_error.rb +31 -0
- data/test/solvebio/test_filter.rb +86 -0
- data/test/solvebio/test_query.rb +282 -0
- data/test/solvebio/test_query_batch.rb +38 -0
- data/test/solvebio/test_query_init.rb +30 -0
- data/test/solvebio/test_query_tabulate.rb +73 -0
- data/test/solvebio/test_ratelimit.rb +31 -0
- data/test/solvebio/test_resource.rb +29 -0
- data/test/solvebio/test_sample_access.rb +60 -0
- data/test/solvebio/test_sample_download.rb +20 -0
- data/test/solvebio/test_tabulate.rb +129 -0
- data/test/solvebio/test_util.rb +39 -0
- metadata +100 -85
- data/Makefile +0 -17
- data/demo/README.md +0 -14
- data/demo/cheatsheet.rb +0 -31
- data/demo/dataset/facets.rb +0 -13
- data/demo/dataset/field.rb +0 -13
- data/demo/depository/README.md +0 -24
- data/demo/depository/all.rb +0 -13
- data/demo/depository/retrieve.rb +0 -13
- data/demo/depository/versions-all.rb +0 -13
- data/demo/query/query-filter.rb +0 -30
- data/demo/query/query.rb +0 -13
- data/demo/query/range-filter.rb +0 -18
- data/demo/test-api.rb +0 -98
- data/lib/cli/auth.rb +0 -122
- data/lib/cli/help.rb +0 -13
- data/lib/cli/irbrc.rb +0 -54
- data/lib/cli/options.rb +0 -75
- data/lib/client.rb +0 -154
- data/lib/credentials.rb +0 -67
- data/lib/errors.rb +0 -81
- data/lib/filter.rb +0 -312
- data/lib/locale.rb +0 -47
- data/lib/main.rb +0 -46
- data/lib/query.rb +0 -414
- data/lib/resource/annotation.rb +0 -23
- data/lib/resource/apiresource.rb +0 -241
- data/lib/resource/dataset.rb +0 -91
- data/lib/resource/datasetfield.rb +0 -37
- data/lib/resource/depository.rb +0 -50
- data/lib/resource/depositoryversion.rb +0 -69
- data/lib/resource/main.rb +0 -123
- data/lib/resource/sample.rb +0 -75
- data/lib/resource/solveobject.rb +0 -122
- data/lib/resource/user.rb +0 -5
- data/lib/tabulate.rb +0 -706
- data/lib/util.rb +0 -29
- data/test/Makefile +0 -9
- data/test/data/sample.vcf.gz +0 -0
- data/test/test-annotation.rb +0 -46
- data/test/test-auth.rb +0 -58
- data/test/test-client.rb +0 -27
- data/test/test-conversion.rb +0 -13
- data/test/test-dataset.rb +0 -42
- data/test/test-depository.rb +0 -35
- data/test/test-error.rb +0 -36
- data/test/test-filter.rb +0 -70
- data/test/test-netrc.rb +0 -52
- data/test/test-query-batch.rb +0 -40
- data/test/test-query-init.rb +0 -29
- data/test/test-query-paging.rb +0 -102
- data/test/test-query.rb +0 -71
- data/test/test-resource.rb +0 -40
- data/test/test-sample-access.rb +0 -59
- data/test/test-sample-download.rb +0 -20
- data/test/test-tabulate.rb +0 -131
- data/test/test-util.rb +0 -42
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module SolveBio
|
|
2
|
+
class APIResource < SolveObject
|
|
3
|
+
def self.retrieve(id)
|
|
4
|
+
instance = self.new(id)
|
|
5
|
+
instance.refresh()
|
|
6
|
+
instance
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.class_name
|
|
10
|
+
self.name.split('::')[-1]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.url
|
|
14
|
+
if self == APIResource
|
|
15
|
+
raise NotImplementedError.new('APIResource is an abstract class and has no url.')
|
|
16
|
+
end
|
|
17
|
+
"/v1/#{Util.pluralize(Util.camelcase_to_underscore(class_name))}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def url
|
|
21
|
+
unless id = self.id
|
|
22
|
+
raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
|
|
23
|
+
end
|
|
24
|
+
"#{self.class.url}/#{id}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def refresh
|
|
28
|
+
response = Client.get(url)
|
|
29
|
+
refresh_from(response)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/solvebio/cli.rb
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
require 'irb'
|
|
5
|
+
require 'netrc'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
require 'optparse'
|
|
8
|
+
require 'readline'
|
|
9
|
+
require 'io/console'
|
|
10
|
+
|
|
11
|
+
require 'solvebio/cli/credentials'
|
|
12
|
+
require 'solvebio/cli/auth'
|
|
13
|
+
require 'solvebio/cli/irb'
|
|
14
|
+
require 'solvebio/cli/tutorial'
|
|
15
|
+
|
|
16
|
+
module SolveBio
|
|
17
|
+
module CLI
|
|
18
|
+
def process_options(argv)
|
|
19
|
+
options = {}
|
|
20
|
+
opts = setup_options(options)
|
|
21
|
+
|
|
22
|
+
begin
|
|
23
|
+
opts.parse!(argv)
|
|
24
|
+
rescue OptionParser::ParseError => error
|
|
25
|
+
$stderr.puts error
|
|
26
|
+
$stderr.puts "(-h or --help will show valid options)"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
SolveBio.api_host = options[:api_host] if options[:api_host]
|
|
31
|
+
SolveBio.api_key = options[:api_key] if options[:api_key]
|
|
32
|
+
|
|
33
|
+
return options, argv
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Main parser for the SolveBio command line client
|
|
37
|
+
def setup_options(options, stdout=$stdout, stderr=$stderr)
|
|
38
|
+
OptionParser.new do |opts|
|
|
39
|
+
opts.banner = "Usage: solvebio.rb [options] <command> [<args>]"
|
|
40
|
+
opts.on_tail('-v', '--version',
|
|
41
|
+
'print the version') do
|
|
42
|
+
options[:version] = true
|
|
43
|
+
stdout.puts "solvebio-ruby #{SolveBio::VERSION}"
|
|
44
|
+
exit 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
opts.on('--api-host STRING', String,
|
|
48
|
+
'Override the default SolveBio API host') do
|
|
49
|
+
|api_host|
|
|
50
|
+
options[:api_host] = api_host
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
opts.on('--api-key STRING', String,
|
|
54
|
+
'Manually provide a SolveBio API key') do
|
|
55
|
+
|api_key|
|
|
56
|
+
options[:api_key] = api_key
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
opts.on('-h', '--help', 'Display this screen') do
|
|
60
|
+
puts opts
|
|
61
|
+
puts <<-EOH
|
|
62
|
+
|
|
63
|
+
SolveBio Commands:
|
|
64
|
+
login Login and save credentials.
|
|
65
|
+
logout Logout and delete saved credentials.
|
|
66
|
+
whoami Show your SolveBio email address.
|
|
67
|
+
shell Open a SolveBio IRB shell.
|
|
68
|
+
tutorial Start the SolveBio Ruby tutorial.
|
|
69
|
+
EOH
|
|
70
|
+
exit
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
module SolveBio
|
|
2
|
+
module CLI
|
|
3
|
+
module Auth
|
|
4
|
+
include SolveBio::CLI::Credentials
|
|
5
|
+
|
|
6
|
+
module_function
|
|
7
|
+
def print_message(msg)
|
|
8
|
+
if SolveBio.api_host != 'https://api.solvebio.com'
|
|
9
|
+
msg += " (#{SolveBio.api_host})"
|
|
10
|
+
end
|
|
11
|
+
puts msg + '.'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ask_for_credentials()
|
|
15
|
+
print_message('Enter your SolveBio credentials')
|
|
16
|
+
email = Readline.readline('Email: ', true)
|
|
17
|
+
puts 'Password (typing will be hidden): '
|
|
18
|
+
password = STDIN.noecho(&:gets).chomp
|
|
19
|
+
puts
|
|
20
|
+
return email, password
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def send_install_report
|
|
24
|
+
require 'rbconfig';
|
|
25
|
+
data = {
|
|
26
|
+
:client => 'ruby',
|
|
27
|
+
:client_version => SolveBio::VERSION,
|
|
28
|
+
:ruby_version => RbConfig::CONFIG['RUBY_PROGRAM_VERSION'],
|
|
29
|
+
:ruby_implementation => RbConfig::CONFIG['RUBY_SO_NAME'],
|
|
30
|
+
:architecture => RbConfig::CONFIG['arch'],
|
|
31
|
+
}
|
|
32
|
+
Client.request('post', '/v1/reports/install', {:payload => data}) rescue nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def login
|
|
36
|
+
email, password = ask_for_credentials
|
|
37
|
+
|
|
38
|
+
if not email or not password
|
|
39
|
+
puts "Email and password are both required."
|
|
40
|
+
return false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
data = {
|
|
44
|
+
:email => email,
|
|
45
|
+
:password => password
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
response = Client.post('/v1/auth/token', {:payload => data})
|
|
50
|
+
rescue SolveBio::SolveError => e
|
|
51
|
+
puts "Login failed: #{e.to_s}"
|
|
52
|
+
return false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
delete_credentials
|
|
56
|
+
save_credentials(email.downcase, response[:token])
|
|
57
|
+
SolveBio.api_key = response[:token]
|
|
58
|
+
send_install_report
|
|
59
|
+
print_message("You are now logged-in as #{email}")
|
|
60
|
+
return true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def logout
|
|
64
|
+
if get_credentials
|
|
65
|
+
delete_credentials
|
|
66
|
+
print_message('You have been logged out')
|
|
67
|
+
return true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
print_message('You are not logged-in')
|
|
71
|
+
return false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def whoami
|
|
75
|
+
email = nil
|
|
76
|
+
api_key = SolveBio.api_key
|
|
77
|
+
|
|
78
|
+
# Override local credentials with existing key
|
|
79
|
+
if SolveBio.api_key
|
|
80
|
+
begin
|
|
81
|
+
user = Client.get('/v1/user')
|
|
82
|
+
email = user[:email]
|
|
83
|
+
rescue SolveBio::SolveError => e
|
|
84
|
+
SolveBio.api_key = nil
|
|
85
|
+
api_key = nil
|
|
86
|
+
print_message("Error: #{e.to_s}")
|
|
87
|
+
end
|
|
88
|
+
else
|
|
89
|
+
begin
|
|
90
|
+
email, api_key = get_credentials
|
|
91
|
+
rescue
|
|
92
|
+
nil
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if not email.nil?
|
|
97
|
+
print_message("You are logged-in as #{email}")
|
|
98
|
+
else
|
|
99
|
+
print_message("You are not logged-in")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
return email, api_key
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
class CredentialsError < RuntimeError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module SolveBio
|
|
8
|
+
module CLI
|
|
9
|
+
module Credentials
|
|
10
|
+
module_function
|
|
11
|
+
def api_host
|
|
12
|
+
Addressable::URI.parse(SolveBio.api_host).host
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def netrc_path
|
|
16
|
+
raise IOError, "$HOME is not set and is needed for SolveBio credentials" unless
|
|
17
|
+
ENV['HOME']
|
|
18
|
+
|
|
19
|
+
path = File.join(ENV['HOME'], '.solvebio', 'credentials')
|
|
20
|
+
|
|
21
|
+
dirname = File.dirname(path)
|
|
22
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
|
23
|
+
|
|
24
|
+
# create an empty credentials file if it doesn't exist
|
|
25
|
+
FileUtils.touch path unless File.exist? path
|
|
26
|
+
FileUtils.chmod 0600, path
|
|
27
|
+
path
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_credentials
|
|
31
|
+
begin
|
|
32
|
+
n = Netrc.read(netrc_path)
|
|
33
|
+
return n[api_host]
|
|
34
|
+
rescue Netrc::Error => e
|
|
35
|
+
raise CredentialsError, "Could not read credentials file: #{e}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
module_function :get_credentials
|
|
39
|
+
|
|
40
|
+
def delete_credentials
|
|
41
|
+
n = Netrc.read(netrc_path)
|
|
42
|
+
n.delete(api_host)
|
|
43
|
+
n.save
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def save_credentials(email, api_key)
|
|
47
|
+
n = Netrc.read(netrc_path)
|
|
48
|
+
# Overwrites any existing credentials
|
|
49
|
+
n[api_host] = email, api_key
|
|
50
|
+
n.save
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
-
# Open the SolveBio shell, an IRB wrapper
|
|
4
|
-
require 'irb'
|
|
5
|
-
require_relative 'help'
|
|
6
3
|
|
|
7
4
|
module IRB
|
|
8
|
-
|
|
9
|
-
# Stuff to add IRB commands goes here
|
|
10
|
-
# module ExtendCommand
|
|
11
|
-
# class SolveHelp
|
|
12
|
-
# def self.execute(conf, *opts)
|
|
13
|
-
# SolveBio::help
|
|
14
|
-
# end
|
|
15
|
-
# end
|
|
16
|
-
|
|
17
|
-
# end
|
|
18
|
-
|
|
19
5
|
module_function
|
|
20
|
-
|
|
21
|
-
# ExtendCommandBundle.def_extend_command 'solvehelp', :SolveHelp
|
|
22
|
-
|
|
23
6
|
def shell
|
|
24
|
-
|
|
25
7
|
# Set to run the standard trepan IRB profile
|
|
26
8
|
irbrc = File.
|
|
27
9
|
expand_path(File.join(File.dirname(__FILE__), 'irbrc.rb'))
|
|
@@ -51,8 +33,3 @@ module IRB
|
|
|
51
33
|
end
|
|
52
34
|
end
|
|
53
35
|
end
|
|
54
|
-
|
|
55
|
-
# Demo it.
|
|
56
|
-
if __FILE__ == $0
|
|
57
|
-
IRB::shell
|
|
58
|
-
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
# irbrc profile for SolveBio
|
|
3
|
+
IRB.conf[:PROMPT_MODE] = :SIMPLE
|
|
4
|
+
IRB.conf[:PROMPT][:SIMPLE] = {
|
|
5
|
+
:PROMPT_C => '[SolveBio] In ?: ', # Prompt when continuing a statement
|
|
6
|
+
:PROMPT_I => '[SolveBio] In : ', # Normal prompt
|
|
7
|
+
:PROMPT_N => '[SolveBio] In +: ', # Prompt when indenting code
|
|
8
|
+
:PROMPT_S => '[SolveBio] In %l: ', # Prompt when continuing a string
|
|
9
|
+
:RETURN => "[SolveBio] Out : %s\n"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
require 'solvebio'
|
|
13
|
+
require 'solvebio/cli'
|
|
14
|
+
|
|
15
|
+
have_completion = nil
|
|
16
|
+
begin
|
|
17
|
+
require 'bond' and require 'bond/completion'
|
|
18
|
+
have_completion = 'bond'
|
|
19
|
+
rescue LoadError
|
|
20
|
+
begin
|
|
21
|
+
have_completion = require 'irb/completion'
|
|
22
|
+
rescue LoadError
|
|
23
|
+
have_completion = false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
unless have_completion
|
|
28
|
+
if have_completion != 'bond'
|
|
29
|
+
puts "Please install the 'bond' getm for better autocompletion"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# If an API key is set in SolveBio.api_key, use that.
|
|
34
|
+
# Otherwise, look for credentials in the local file,
|
|
35
|
+
# Otherwise, ask the user to log in.
|
|
36
|
+
|
|
37
|
+
if SolveBio.api_key or SolveBio::CLI::Credentials.get_credentials
|
|
38
|
+
email, SolveBio.api_key = SolveBio::CLI::Auth::whoami
|
|
39
|
+
else
|
|
40
|
+
SolveBio::CLI::Auth.login
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if not SolveBio.api_key
|
|
44
|
+
puts("SolveBio requires a valid account. To sign up, visit: https://www.solvebio.com/signup")
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
include SolveBio
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
module SolveBio
|
|
2
|
+
class Client
|
|
3
|
+
attr_reader :headers, :api_host
|
|
4
|
+
attr_accessor :api_key
|
|
5
|
+
|
|
6
|
+
# Add our own kind of Authorization tokens. This has to be
|
|
7
|
+
# done this way, late, because the rest-client gem looks for
|
|
8
|
+
# .netrc and will set basic authentication if it finds a match.
|
|
9
|
+
RestClient.add_before_execution_proc do | req, args |
|
|
10
|
+
if args[:authorization]
|
|
11
|
+
req.instance_variable_get('@header')['authorization'] = [args[:authorization]]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(api_key=nil, api_host=nil)
|
|
16
|
+
@api_key = api_key || SolveBio.api_key
|
|
17
|
+
@api_host = api_host || SolveBio.api_host
|
|
18
|
+
|
|
19
|
+
# Mirroring comments from:
|
|
20
|
+
# http://ruby-doc.org/stdlib-2.1.2/libdoc/net/http/rdoc/Net/HTTP.html
|
|
21
|
+
# gzip compression is used in preference to deflate
|
|
22
|
+
# compression, which is used in preference to no compression.
|
|
23
|
+
@headers = {
|
|
24
|
+
:content_type => :json,
|
|
25
|
+
:accept => :json,
|
|
26
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
|
27
|
+
'User-Agent' => 'SolveBio Ruby Client %s' % [
|
|
28
|
+
SolveBio::VERSION,
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
DEFAULT_REQUEST_OPTS = {
|
|
34
|
+
:raw => false,
|
|
35
|
+
:default_headers => true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Issues an HTTP GET across the wire via the Ruby 'rest-client'
|
|
39
|
+
# library. See *request()* for information on opts.
|
|
40
|
+
def get(url, opts={})
|
|
41
|
+
request('get', url, opts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Issues an HTTP POST across the wire via the Ruby 'rest-client'
|
|
45
|
+
# library. See *request* for information on opts.
|
|
46
|
+
def post(url, data, opts={})
|
|
47
|
+
opts[:payload] =
|
|
48
|
+
if opts.member?(:no_json)
|
|
49
|
+
data
|
|
50
|
+
else
|
|
51
|
+
data.to_json
|
|
52
|
+
end
|
|
53
|
+
request('post', url, opts)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Issues an HTTP Request across the wire via the Ruby 'rest-client'
|
|
57
|
+
# library.
|
|
58
|
+
def request(method, url, opts={})
|
|
59
|
+
opts = DEFAULT_REQUEST_OPTS.merge(opts)
|
|
60
|
+
|
|
61
|
+
# Expand URL with API host if none was given
|
|
62
|
+
api_host = @api_host or SolveBio.api_host
|
|
63
|
+
|
|
64
|
+
if not api_host
|
|
65
|
+
raise SolveError.new('No SolveBio API host is set')
|
|
66
|
+
elsif not url.start_with?(api_host)
|
|
67
|
+
url = Addressable::URI.join(api_host, url).to_s
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Handle some default options and add authorization header
|
|
71
|
+
if opts[:default_headers] and @api_key
|
|
72
|
+
headers = @headers.merge(opts[:headers]||{})
|
|
73
|
+
authorization = "Token #{@api_key}"
|
|
74
|
+
else
|
|
75
|
+
headers = nil
|
|
76
|
+
authorization = nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
SolveBio::logger.debug('API %s Request: %s' % [method.upcase, url])
|
|
80
|
+
|
|
81
|
+
response = nil
|
|
82
|
+
begin
|
|
83
|
+
RestClient::Request.
|
|
84
|
+
execute(:method => method,
|
|
85
|
+
:url => url,
|
|
86
|
+
:headers => headers,
|
|
87
|
+
:authorization => authorization,
|
|
88
|
+
:timeout => opts[:timeout] || 80,
|
|
89
|
+
:payload => opts[:payload]) do
|
|
90
|
+
|resp, request, result, &block|
|
|
91
|
+
response = resp
|
|
92
|
+
if 429 == response.code
|
|
93
|
+
delay = Integer(response.headers[:retry_after])
|
|
94
|
+
SolveBio::logger.warn("Too many requests, sleeping for #{delay}s.")
|
|
95
|
+
sleep(delay)
|
|
96
|
+
return request(method, url, opts)
|
|
97
|
+
elsif response.code < 200 or response.code >= 400
|
|
98
|
+
handle_api_error(response)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
rescue RestClient::Exception => e
|
|
102
|
+
handle_request_error(e)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if opts[:raw]
|
|
106
|
+
return response
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
begin
|
|
110
|
+
response = JSON.parse(response)
|
|
111
|
+
rescue JSON::ParserError => e
|
|
112
|
+
handle_request_error(e)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
Util.symbolize_names(response)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def handle_request_error(e)
|
|
119
|
+
err = e.inspect
|
|
120
|
+
SolveBio::logger.error("API Error: #{err}")
|
|
121
|
+
msg = "Unexpected error communicating with SolveBio.\n" +
|
|
122
|
+
"If this problem persists, let us " +
|
|
123
|
+
"know at contact@solvebio.com."
|
|
124
|
+
raise SolveError.new(nil, msg)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def handle_api_error(response)
|
|
128
|
+
SolveBio::logger.error("API Error: #{response}") unless
|
|
129
|
+
[400, 401, 403, 404].member?(response.code.to_i)
|
|
130
|
+
raise SolveError.new(response)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.client
|
|
134
|
+
@@client ||= SolveBio::Client.new()
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.get(url, opts={})
|
|
138
|
+
client.get(url, opts)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.post(url, data, opts={})
|
|
142
|
+
client.post(url, data, opts)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.request(method, url, opts={})
|
|
146
|
+
client.request(method, url, opts)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|