bio-basespace-sdk 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bio-basespace-sdk might be problematic. Click here for more details.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +16 -0
- data/License.txt +275 -0
- data/README.md +671 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/examples/0_app_triggering.rb +135 -0
- data/examples/1_authentication.rb +156 -0
- data/examples/2_browsing.rb +84 -0
- data/examples/3_accessing_files.rb +129 -0
- data/examples/4_app_result_upload.rb +102 -0
- data/examples/5_purchasing.rb +119 -0
- data/lib/basespace.rb +126 -0
- data/lib/basespace/api/api_client.rb +313 -0
- data/lib/basespace/api/base_api.rb +242 -0
- data/lib/basespace/api/basespace_api.rb +789 -0
- data/lib/basespace/api/basespace_error.rb +80 -0
- data/lib/basespace/api/billing_api.rb +115 -0
- data/lib/basespace/model.rb +78 -0
- data/lib/basespace/model/app_result.rb +158 -0
- data/lib/basespace/model/app_result_response.rb +40 -0
- data/lib/basespace/model/app_session.rb +99 -0
- data/lib/basespace/model/app_session_compact.rb +43 -0
- data/lib/basespace/model/app_session_launch_object.rb +58 -0
- data/lib/basespace/model/app_session_response.rb +41 -0
- data/lib/basespace/model/application.rb +47 -0
- data/lib/basespace/model/application_compact.rb +44 -0
- data/lib/basespace/model/basespace_model.rb +60 -0
- data/lib/basespace/model/coverage.rb +48 -0
- data/lib/basespace/model/coverage_meta_response.rb +40 -0
- data/lib/basespace/model/coverage_metadata.rb +43 -0
- data/lib/basespace/model/coverage_response.rb +40 -0
- data/lib/basespace/model/file.rb +172 -0
- data/lib/basespace/model/file_response.rb +40 -0
- data/lib/basespace/model/genome_response.rb +40 -0
- data/lib/basespace/model/genome_v1.rb +56 -0
- data/lib/basespace/model/list_response.rb +53 -0
- data/lib/basespace/model/multipart_upload.rb +288 -0
- data/lib/basespace/model/product.rb +50 -0
- data/lib/basespace/model/project.rb +103 -0
- data/lib/basespace/model/project_response.rb +40 -0
- data/lib/basespace/model/purchase.rb +89 -0
- data/lib/basespace/model/purchase_response.rb +39 -0
- data/lib/basespace/model/purchased_product.rb +56 -0
- data/lib/basespace/model/query_parameters.rb +86 -0
- data/lib/basespace/model/query_parameters_purchased_product.rb +67 -0
- data/lib/basespace/model/refund_purchase_response.rb +40 -0
- data/lib/basespace/model/resource_list.rb +48 -0
- data/lib/basespace/model/response_status.rb +42 -0
- data/lib/basespace/model/run_compact.rb +55 -0
- data/lib/basespace/model/sample.rb +127 -0
- data/lib/basespace/model/sample_response.rb +40 -0
- data/lib/basespace/model/user.rb +80 -0
- data/lib/basespace/model/user_compact.rb +45 -0
- data/lib/basespace/model/user_response.rb +40 -0
- data/lib/basespace/model/variant.rb +57 -0
- data/lib/basespace/model/variant_header.rb +44 -0
- data/lib/basespace/model/variant_info.rb +48 -0
- data/lib/basespace/model/variants_header_response.rb +40 -0
- data/spec/basespaceapi_spec.rb +26 -0
- data/spec/basespaceerror_spec.rb +87 -0
- data/spec/basespacemodel_spec.rb +57 -0
- metadata +239 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2013 Toshiaki Katayama, Joachim Baran
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Creating an AppResult and uploading files
|
17
|
+
# https://developer.basespace.illumina.com/docs/content/documentation/sdk-samples/python-sdk-overview#Creating_an_AppResult_and_uploading_files
|
18
|
+
|
19
|
+
require 'basespace'
|
20
|
+
|
21
|
+
include Bio::BaseSpace
|
22
|
+
|
23
|
+
# This script demonstrates how to create a new AppResults object, change its state
|
24
|
+
# and upload result files to it and download files from it.
|
25
|
+
|
26
|
+
opts = {
|
27
|
+
# FILL IN WITH YOUR APP VALUES HERE!
|
28
|
+
'client_id' => '<your client key>',
|
29
|
+
'client_secret' => '<your client secret>',
|
30
|
+
'access_token' => '<your access token>',
|
31
|
+
'app_session_id' => '<app session id>',
|
32
|
+
'basespace_url' => 'https://api.basespace.illumina.com/',
|
33
|
+
'api_version' => 'v1pre3',
|
34
|
+
}
|
35
|
+
|
36
|
+
# Test if client variables have been set.
|
37
|
+
unless opts.select{|k,v| v[/^<.*>$/]}.empty?
|
38
|
+
opts = Bio::BaseSpace.load_credentials
|
39
|
+
exit 1 unless opts
|
40
|
+
end
|
41
|
+
|
42
|
+
# First, create a client for making calls for this user session.
|
43
|
+
bs_api = BaseSpaceAPI.new(opts['client_id'], opts['client_secret'], opts['basespace_url'], opts['api_version'], opts['app_session_id'], opts['access_token'])
|
44
|
+
|
45
|
+
# Now we'll do some work of our own. First get a project to work on.
|
46
|
+
# We need write permission for the project we are working on,
|
47
|
+
# meaning we will need get a new token and instantiate a new BaseSpaceAPI.
|
48
|
+
prj = bs_api.get_project_by_id('89') # [TODO] Original ID '89' was not accessible. Writable project is needed.
|
49
|
+
|
50
|
+
# Assuming we have write access to the project
|
51
|
+
# we list the current App Results for the project.
|
52
|
+
statuses = ['Running']
|
53
|
+
app_res = prj.get_app_results(bs_api, {}, statuses) # [TODO] should introduce hash options / keyword arguments (in Ruby 2.0)
|
54
|
+
puts "The current running AppResults are #{app_res}"
|
55
|
+
puts
|
56
|
+
|
57
|
+
#
|
58
|
+
# Retrieving results and setting status
|
59
|
+
#
|
60
|
+
|
61
|
+
# To create an appResults for a project, simply give the name and description.
|
62
|
+
app_results = prj.create_app_result(bs_api, "testing", "this is my results")
|
63
|
+
puts "Some info about our new app results"
|
64
|
+
puts app_results
|
65
|
+
puts app_results.id
|
66
|
+
puts
|
67
|
+
puts "The app results also comes with a reference to our AppSession"
|
68
|
+
my_app_session = app_results.app_session
|
69
|
+
puts my_app_session
|
70
|
+
puts
|
71
|
+
|
72
|
+
# We can change the status of our AppSession and add a status-summary as follows.
|
73
|
+
my_app_session.set_status(bs_api, 'needsattention', "We worked hard, but encountered some trouble.")
|
74
|
+
puts "After a change of status of the app sessions we get #{my_app_session}"
|
75
|
+
puts
|
76
|
+
# We set our appSession back to running so we can do some more work.
|
77
|
+
my_app_session.set_status(bs_api, 'running', "Back on track")
|
78
|
+
|
79
|
+
|
80
|
+
# Let's list all AppResults again and see if our new object shows up.
|
81
|
+
app_res = prj.get_app_results(bs_api, {}, ['Running'])
|
82
|
+
puts "The updated app results are #{app_res}"
|
83
|
+
app_result2 = bs_api.get_app_result_by_id(app_results.id)
|
84
|
+
puts app_result2
|
85
|
+
puts
|
86
|
+
|
87
|
+
# Now we will make another AppResult and try to upload a file to it
|
88
|
+
app_results2 = prj.create_app_result(bs_api, "My second AppResult", "This one I will upload to")
|
89
|
+
app_results2.upload_file(bs_api, '/home/mkallberg/Desktop/testFile2.txt', 'BaseSpaceTestFile.txt', '/mydir/', 'text/plain')
|
90
|
+
puts "My AppResult number 2 #{app_results2}"
|
91
|
+
puts
|
92
|
+
|
93
|
+
# Let's see if our new file made it.
|
94
|
+
app_result_files = app_results2.get_files(bs_api)
|
95
|
+
puts "These are the files in the appResult"
|
96
|
+
puts app_result_files
|
97
|
+
f = app_result_files.last
|
98
|
+
|
99
|
+
# We can even download our newly uploaded file.
|
100
|
+
f = bs_api.get_file_by_id(f.id)
|
101
|
+
f.download_file(bs_api, '/home/mkallberg/Desktop/')
|
102
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2013 Toshiaki Katayama, Joachim Baran
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'basespace'
|
17
|
+
|
18
|
+
include Bio::BaseSpace
|
19
|
+
|
20
|
+
# This example demonstrates the billing methods of BaseSpace.
|
21
|
+
#
|
22
|
+
# Below a purchase is created, requiring the user to click 'Purchase' in a web
|
23
|
+
# browser. The purchase is then refunded, and the purchase is again retrieved
|
24
|
+
# via the API using the purchase id and tags, which are used by developers
|
25
|
+
# to help clarify exactly what was purchased.
|
26
|
+
#
|
27
|
+
# NOTE You will need to fill client values for your app below!
|
28
|
+
|
29
|
+
opts = {
|
30
|
+
# FILL IN WITH YOUR APP VALUES HERE!
|
31
|
+
'client_id' => '<your client key>', # from dev portal app Credentials tab
|
32
|
+
'client_secret' => '<your client secret>', # from dev portal app Credentials tab
|
33
|
+
'access_token' => '<your access token>', # from oauth2
|
34
|
+
'app_session_id' => '<app session id>', # from launching an app
|
35
|
+
'basespace_url' => 'https://api.basespace.illumina.com/',
|
36
|
+
'api_version' => 'v1pre3',
|
37
|
+
'basespace_store_url' => 'https://hoth-store.basespace.illumina.com/',
|
38
|
+
'product_id' => '', # from dev portal Pricing tab
|
39
|
+
}
|
40
|
+
|
41
|
+
# Test if client variables have been set.
|
42
|
+
unless opts.select{|k,v| v[/^<.*>$/]}.empty?
|
43
|
+
opts = Bio::BaseSpace.load_credentials
|
44
|
+
exit 1 unless opts
|
45
|
+
end
|
46
|
+
|
47
|
+
unless opts['client_id'] or opts['product_id']
|
48
|
+
raise "Please fill in client values (in the script) before running the script"
|
49
|
+
end
|
50
|
+
|
51
|
+
# First, create a client for making calls for this user session.
|
52
|
+
bill_api = BillingAPI.new(opts['basespace_store_url'], opts['api_version'], opts['app_session_id'], opts['access_token'])
|
53
|
+
|
54
|
+
# Create a non-consumable purchase.
|
55
|
+
#purch = bill_api.create_purchase([{'id':product_id,'quantity':4 }])
|
56
|
+
|
57
|
+
# Create a consumable purchase, and associated it with an AppSession
|
58
|
+
# also add tags to provide (fake) details about the purchase.
|
59
|
+
puts "Creating purchase"
|
60
|
+
# purch = billAPI.createPurchase({'id':product_id,'quantity':4, 'tags':["test","test_tag"] }, AppSessionId)
|
61
|
+
products = {
|
62
|
+
'id' => opts['product_id'],
|
63
|
+
'quantity' => 4,
|
64
|
+
'tags' => ["test", "test_tag"],
|
65
|
+
}
|
66
|
+
purch = bill_api.create_purchase(products, opts['app_session_id'])
|
67
|
+
|
68
|
+
# Record the purchase Id and RefundSecret for refunding later.
|
69
|
+
purchase_id = purch.id
|
70
|
+
refund_secret = purch.refund_secret
|
71
|
+
|
72
|
+
puts "Now complete the purchase in your web browser"
|
73
|
+
puts "CLOSE the browser window/tab after you click 'Purchase' (and don't proceed into the app)"
|
74
|
+
time.sleep(3)
|
75
|
+
## PAUSE HERE
|
76
|
+
link = purch.href_purchase_dialog
|
77
|
+
puts "Opening: #{link}"
|
78
|
+
host = RbConfig::CONFIG['host_os']
|
79
|
+
case host
|
80
|
+
when /mswin|mingw|cygwin/
|
81
|
+
system("start #{link}")
|
82
|
+
when /darwin/
|
83
|
+
system("open #{link}")
|
84
|
+
when /linux/
|
85
|
+
system("xdg-open #{link}")
|
86
|
+
end
|
87
|
+
puts "Waiting 30 seconds..."
|
88
|
+
time.sleep(30)
|
89
|
+
## PAUSE HERE
|
90
|
+
|
91
|
+
puts "Confirm the purchase"
|
92
|
+
post_purch = bill_api.get_purchase_by_id(purchase_id)
|
93
|
+
puts "The status of the purchase is now: " + post_purch.status
|
94
|
+
puts
|
95
|
+
|
96
|
+
puts "Refunding the Purchase"
|
97
|
+
puts
|
98
|
+
# NOTE We must use the same access token that was provided used for the purchase.
|
99
|
+
refunded_purchase = bill_api.refund_purchase(purchase_id, refund_secret, 'the product did not function well as a frisbee')
|
100
|
+
|
101
|
+
puts "Getting all purchases for the current user with the tags we used for the purchase above"
|
102
|
+
puts
|
103
|
+
#purch_prods = bill_api.get_user_products
|
104
|
+
purch_prods = bill_api.get_user_products('current', {'Tags' => 'test,test_tag'})
|
105
|
+
if purch_prods.nil? or purch_prods.empty?
|
106
|
+
puts "Hmmm, didn't find any purchases with these tags. Did everything go OK above?"
|
107
|
+
else
|
108
|
+
puts "For the first of these purchases:"
|
109
|
+
puts "Purchase Name: #{purch_prods[0].name}"
|
110
|
+
puts "Purchase Price: #{purch_prods[0].price}"
|
111
|
+
puts "Purchase Quantity: #{purch_prods[0].quantity}"
|
112
|
+
puts "Tags: #{purch_prods[0].tags}"
|
113
|
+
# Get the refund status of the purchase
|
114
|
+
puts "Getting the (refunded) Purchase we just made"
|
115
|
+
get_purch = bill_api.get_purchase_by_id(purch_prods[0].purchase_id)
|
116
|
+
puts "Refund Status: #{get_purch.refund_status}"
|
117
|
+
end
|
118
|
+
|
119
|
+
|
data/lib/basespace.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# Copyright 2012-2013 Joachim Baran, Raoul Bonnal, Toshiaki Katayama, Francesco Strozzi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
# See the License for the specific language governing permissions and
|
12
|
+
# limitations under the License.
|
13
|
+
|
14
|
+
# Still need to check [TODO] sections
|
15
|
+
|
16
|
+
require 'basespace/api/api_client'
|
17
|
+
require 'basespace/api/base_api'
|
18
|
+
require 'basespace/api/billing_api'
|
19
|
+
require 'basespace/api/basespace_api'
|
20
|
+
require 'basespace/api/basespace_error'
|
21
|
+
|
22
|
+
require 'basespace/model'
|
23
|
+
require 'basespace/model/app_result'
|
24
|
+
require 'basespace/model/app_result_response'
|
25
|
+
require 'basespace/model/app_session'
|
26
|
+
require 'basespace/model/app_session_compact'
|
27
|
+
require 'basespace/model/app_session_launch_object'
|
28
|
+
require 'basespace/model/app_session_response'
|
29
|
+
require 'basespace/model/application'
|
30
|
+
require 'basespace/model/application_compact'
|
31
|
+
require 'basespace/model/basespace_model'
|
32
|
+
require 'basespace/model/coverage'
|
33
|
+
require 'basespace/model/coverage_meta_response'
|
34
|
+
require 'basespace/model/coverage_metadata'
|
35
|
+
require 'basespace/model/coverage_response'
|
36
|
+
require 'basespace/model/file'
|
37
|
+
require 'basespace/model/file_response'
|
38
|
+
require 'basespace/model/genome_response'
|
39
|
+
require 'basespace/model/genome_v1'
|
40
|
+
require 'basespace/model/list_response'
|
41
|
+
#require 'basespace/model/multipart_upload'
|
42
|
+
require 'basespace/model/product'
|
43
|
+
require 'basespace/model/project'
|
44
|
+
require 'basespace/model/project_response'
|
45
|
+
require 'basespace/model/purchase'
|
46
|
+
require 'basespace/model/purchase_response'
|
47
|
+
require 'basespace/model/purchased_product'
|
48
|
+
require 'basespace/model/query_parameters'
|
49
|
+
require 'basespace/model/query_parameters_purchased_product'
|
50
|
+
require 'basespace/model/refund_purchase_response'
|
51
|
+
require 'basespace/model/resource_list'
|
52
|
+
require 'basespace/model/response_status'
|
53
|
+
require 'basespace/model/run_compact'
|
54
|
+
require 'basespace/model/sample'
|
55
|
+
require 'basespace/model/sample_response'
|
56
|
+
require 'basespace/model/user'
|
57
|
+
require 'basespace/model/user_compact'
|
58
|
+
require 'basespace/model/user_response'
|
59
|
+
require 'basespace/model/variant'
|
60
|
+
require 'basespace/model/variant_header'
|
61
|
+
require 'basespace/model/variant_info'
|
62
|
+
require 'basespace/model/variants_header_response'
|
63
|
+
|
64
|
+
require 'json'
|
65
|
+
|
66
|
+
module Bio
|
67
|
+
|
68
|
+
# BaseSpace Ruby SDK is to be used in the development of Apps and scripts
|
69
|
+
# for working with Illumina's BaseSpace cloud-computing solution for next-gen
|
70
|
+
# sequencing data analysis.
|
71
|
+
module BaseSpace
|
72
|
+
|
73
|
+
# Loads login and authentication credentials from a JSON file.
|
74
|
+
#
|
75
|
+
# If the environment variable "BASESPACE_CREDENTIALS" is set, then the
|
76
|
+
# path to the JSON files is taken from there. Otherwise, the current
|
77
|
+
# directory is searched for the file "credentials.json".
|
78
|
+
#
|
79
|
+
# On success, returns a hash with the values for
|
80
|
+
# * client_id
|
81
|
+
# * client_secret
|
82
|
+
# * access_token
|
83
|
+
# * app_session_id
|
84
|
+
# * basespace_url
|
85
|
+
# * api_version
|
86
|
+
#
|
87
|
+
# On failure, returns nil.
|
88
|
+
def self.load_credentials
|
89
|
+
filename = "credentials.json"
|
90
|
+
if ENV['BASESPACE_CREDENTIALS']
|
91
|
+
jsonfile = ENV['BASESPACE_CREDENTIALS']
|
92
|
+
else
|
93
|
+
jsonfile = ::File.join('.', filename)
|
94
|
+
end
|
95
|
+
if ::File.exists?(jsonfile)
|
96
|
+
hash = JSON.parse(::File.read(jsonfile))
|
97
|
+
if $DEBUG
|
98
|
+
$stderr.puts " # ----- Bio::BaseSpace.load_credientials ----- "
|
99
|
+
$stderr.puts " # Loaded credentials from #{jsonfile}"
|
100
|
+
$stderr.puts " # "
|
101
|
+
end
|
102
|
+
else
|
103
|
+
hash = nil
|
104
|
+
$stderr.puts " # ----- Bio::BaseSpace.load_credientials ----- "
|
105
|
+
$stderr.puts " # You can put your credentials for the BaseSpace in the"
|
106
|
+
$stderr.puts " # #{jsonfile}"
|
107
|
+
$stderr.puts " # file or point to the file with an environmental variable"
|
108
|
+
$stderr.puts " # export BASESPACE_CREDENTIALS=/path/to/your/#{filename}"
|
109
|
+
$stderr.puts " # in the following format:"
|
110
|
+
data = {
|
111
|
+
'client_id' => '<your client id>',
|
112
|
+
'client_secret' => '<your client secret>',
|
113
|
+
'access_token' => '<your access token>',
|
114
|
+
'app_session_id' => '<app session id>',
|
115
|
+
'basespace_url' => 'https://api.basespace.illumina.com/',
|
116
|
+
'api_version' => 'v1pre3',
|
117
|
+
}
|
118
|
+
$stderr.puts JSON.pretty_generate(JSON.parse(data.to_json))
|
119
|
+
end
|
120
|
+
return hash
|
121
|
+
end
|
122
|
+
|
123
|
+
end # BaseSpace
|
124
|
+
end # Bio
|
125
|
+
|
126
|
+
|
@@ -0,0 +1,313 @@
|
|
1
|
+
# Copyright 2012-2013 Joachim Baran, Toshiaki Katayama
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
# See the License for the specific language governing permissions and
|
12
|
+
# limitations under the License.
|
13
|
+
|
14
|
+
require 'basespace/api/basespace_error'
|
15
|
+
|
16
|
+
require 'net/https'
|
17
|
+
require 'uri'
|
18
|
+
require 'json'
|
19
|
+
require 'date'
|
20
|
+
|
21
|
+
Net::HTTP.version_1_2
|
22
|
+
|
23
|
+
module Bio
|
24
|
+
module BaseSpace
|
25
|
+
|
26
|
+
# This class provides wrapper methods to the BaseSpace API RESTful interface. It also
|
27
|
+
# handles serialization and deserialization of objects (Ruby to/from JSON). It is primarily
|
28
|
+
# used as a helper class for BaseSpaceAPI.
|
29
|
+
class APIClient
|
30
|
+
attr_accessor :api_key, :api_server, :timeout
|
31
|
+
|
32
|
+
# Create a new instance that will carry out REST calls.
|
33
|
+
#
|
34
|
+
# +access_token+:: Access token that is provided by App triggering.
|
35
|
+
# +api_server+:: URI of the BaseSpace API server.
|
36
|
+
# +timeout+:: Timeout for REST calls.
|
37
|
+
def initialize(access_token = nil, api_server = nil, timeout = 10)
|
38
|
+
if $DEBUG
|
39
|
+
$stderr.puts " # ----- BaseAPI#initialize ----- "
|
40
|
+
$stderr.puts " # caller: #{caller}"
|
41
|
+
$stderr.puts " # access_token: #{access_token}"
|
42
|
+
$stderr.puts " # api_server: #{api_server}"
|
43
|
+
$stderr.puts " # timeout: #{timeout}"
|
44
|
+
$stderr.puts " # "
|
45
|
+
end
|
46
|
+
raise UndefinedParameterError.new('AccessToken') unless access_token
|
47
|
+
@api_key = access_token
|
48
|
+
@api_server = api_server
|
49
|
+
@timeout = timeout
|
50
|
+
end
|
51
|
+
|
52
|
+
# POST data to a provided URI.
|
53
|
+
#
|
54
|
+
# +resource_path+:: URI to which the data should be POSTed.
|
55
|
+
# +post_data+:: Hash that contains the data.
|
56
|
+
# +headers+:: Header of the POST call.
|
57
|
+
# +data+:: (unused; TODO)
|
58
|
+
def force_post_call(resource_path, post_data, headers, data = nil)
|
59
|
+
# [TODO] Confirm whether we can expect those two parameters are Hash objects:
|
60
|
+
# headers = { "key" => "value" }
|
61
|
+
# post_data = { "key" => "value" }
|
62
|
+
uri = URI.parse(resource_path)
|
63
|
+
# If headers are not needed, the following line should be enough:
|
64
|
+
# return Net::HTTP.post_form(uri, post_data).body
|
65
|
+
http_opts = {}
|
66
|
+
if uri.scheme == "https"
|
67
|
+
http_opts[:use_ssl] = true
|
68
|
+
end
|
69
|
+
res = Net::HTTP.start(uri.host, uri.port, http_opts) { |http|
|
70
|
+
encoded_data = hash2urlencode(post_data)
|
71
|
+
http.post(uri.path, encoded_data, headers)
|
72
|
+
}
|
73
|
+
return res.body
|
74
|
+
end
|
75
|
+
|
76
|
+
# URL encode a Hash of data values.
|
77
|
+
#
|
78
|
+
# +hash+:: data encoded in a Hash.
|
79
|
+
def hash2urlencode(hash)
|
80
|
+
# URI.escape (alias URI.encode) is obsolete since Ruby 1.9.2.
|
81
|
+
#return hash.map{|k,v| URI.encode(k.to_s) + "=" + URI.encode(v.to_s)}.join("&")
|
82
|
+
return hash.map{|k,v| URI.encode_www_form_component(k.to_s) + "=" + URI.encode_www_form_component(v.to_s)}.join("&")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Makes a PUT call to a given URI for depositing file contents.
|
86
|
+
#
|
87
|
+
# +resource_path+:: URI to which the data should be transferred.
|
88
|
+
# +post_data+:: (unused; TODO)
|
89
|
+
# +headers+:: Header of the PUT call.
|
90
|
+
# +trans_file+:: Path to the file that should be transferred.
|
91
|
+
def put_call(resource_path, post_data, headers, trans_file)
|
92
|
+
return %x(curl -H "x-access-token:#{@api_key}" -H "Content-MD5:#{headers['Content-MD5'].strip}" -T "#{trans_file}" -X PUT #{resource_path})
|
93
|
+
end
|
94
|
+
|
95
|
+
# Deserialize a boolean value to a Ruby object.
|
96
|
+
#
|
97
|
+
# +value+:: serialized representation of the boolean value.
|
98
|
+
def bool(value)
|
99
|
+
case value
|
100
|
+
when nil, false, 0, 'nil', 'false', '0', 'None'
|
101
|
+
result = false
|
102
|
+
else
|
103
|
+
result = true
|
104
|
+
end
|
105
|
+
return result
|
106
|
+
end
|
107
|
+
|
108
|
+
# Carries out a RESTful operation on the BaseSpace API.
|
109
|
+
#
|
110
|
+
# TODO Need check. Logic in this method is rather complicated...
|
111
|
+
#
|
112
|
+
# +resource_path+:: URI that should be used for the API call.
|
113
|
+
# +method+:: HTTP method for the rest call (GET, POST, DELETE, etc.)
|
114
|
+
# +query_params+:: query parameters that should be sent along to the API.
|
115
|
+
# +post_data+:: Hash that contains data to be transferred.
|
116
|
+
# +header_params+:: Additional settings that should be transferred in the HTTP header.
|
117
|
+
# +force_post+:: Truth value that indicates whether a POST should be forced.
|
118
|
+
def call_api(resource_path, method, query_params, post_data, header_params = nil, force_post = false)
|
119
|
+
url = @api_server + resource_path
|
120
|
+
|
121
|
+
headers = header_params.dup
|
122
|
+
headers['Content-Type'] = 'application/json' if not headers.has_key?('Content-Type') and not method == 'PUT'
|
123
|
+
# include access token in header
|
124
|
+
headers['Authorization'] = "Bearer #{@api_key}"
|
125
|
+
|
126
|
+
uri = request = response = data = cgi_params = nil
|
127
|
+
|
128
|
+
if query_params
|
129
|
+
# Need to remove None (in Python, nil in Ruby) values, these should not be sent
|
130
|
+
sent_query_params = {}
|
131
|
+
query_params.each do |param, value|
|
132
|
+
sent_query_params[param] = value if bool(value)
|
133
|
+
end
|
134
|
+
cgi_params = hash2urlencode(sent_query_params)
|
135
|
+
end
|
136
|
+
|
137
|
+
if $DEBUG
|
138
|
+
$stderr.puts " # ----- APIClient#call_api ----- "
|
139
|
+
$stderr.puts " # caller: #{caller}"
|
140
|
+
$stderr.puts " # url: #{url}"
|
141
|
+
$stderr.puts " # method: #{method}"
|
142
|
+
$stderr.puts " # headers: #{headers}"
|
143
|
+
$stderr.puts " # cgi_params: #{cgi_params}"
|
144
|
+
$stderr.puts " # post_data: #{post_data}"
|
145
|
+
$stderr.puts " # "
|
146
|
+
end
|
147
|
+
|
148
|
+
case method
|
149
|
+
when 'GET'
|
150
|
+
if cgi_params
|
151
|
+
url += "?#{cgi_params}"
|
152
|
+
end
|
153
|
+
# [TODO] confirm this works or not
|
154
|
+
#request = urllib2.Request(url, headers)
|
155
|
+
uri = URI.parse(url)
|
156
|
+
request = Net::HTTP::Get.new(uri.path, headers)
|
157
|
+
when 'POST', 'PUT', 'DELETE'
|
158
|
+
if cgi_params
|
159
|
+
force_post_url = url
|
160
|
+
url += "?#{cgi_params}"
|
161
|
+
end
|
162
|
+
if post_data
|
163
|
+
# [TODO] Do we need to skip String, Integer, Float and bool in Ruby?
|
164
|
+
data = post_data.to_json # if not [str, int, float, bool].include?(type(post_data))
|
165
|
+
end
|
166
|
+
if force_post
|
167
|
+
response = force_post_call(force_post_url, sent_query_params, headers)
|
168
|
+
else
|
169
|
+
data = '\n' if data and data.empty? # temp fix, in case is no data in the file, to prevent post request from failing
|
170
|
+
# [TODO] confirm this works or not
|
171
|
+
#request = urllib2.Request(url, headers, data)#, @timeout)
|
172
|
+
uri = URI.parse(url)
|
173
|
+
request = Net::HTTP::Post.new(uri.path, headers)
|
174
|
+
end
|
175
|
+
if ['PUT', 'DELETE'].include?(method) # urllib doesnt do put and delete, default to pycurl here
|
176
|
+
response = put_call(url, query_params, headers, data)
|
177
|
+
response = response.split.last
|
178
|
+
end
|
179
|
+
else
|
180
|
+
raise "Method #{method} is not recognized."
|
181
|
+
end
|
182
|
+
|
183
|
+
# Make the request, request may raise 403 forbidden, or 404 non-response
|
184
|
+
if not force_post and not ['PUT', 'DELETE'].include?(method) # the normal case
|
185
|
+
# puts url
|
186
|
+
# puts request
|
187
|
+
# puts "request with timeout=#{@timeout}"
|
188
|
+
# [TODO] confirm this works or not
|
189
|
+
#response = urllib2.urlopen(request, @timeout).read()
|
190
|
+
http_opts = {}
|
191
|
+
if uri.scheme == "https"
|
192
|
+
http_opts[:use_ssl] = true
|
193
|
+
end
|
194
|
+
response = Net::HTTP.start(uri.host, uri.port, http_opts) { |http|
|
195
|
+
http.request(request)
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
begin
|
200
|
+
data = JSON.parse(response.body)
|
201
|
+
rescue => err
|
202
|
+
$stderr.puts " # ----- APIClient#call_api ----- "
|
203
|
+
$stderr.puts " # Error: #{err}"
|
204
|
+
$stderr.puts " # "
|
205
|
+
data = nil
|
206
|
+
end
|
207
|
+
return data
|
208
|
+
end
|
209
|
+
|
210
|
+
# Serialize a list to a CSV string, if necessary.
|
211
|
+
#
|
212
|
+
# +obj+:: Data object to be serialized.
|
213
|
+
def to_path_value(obj)
|
214
|
+
if obj.kind_of?(Array)
|
215
|
+
return obj.join(',')
|
216
|
+
else
|
217
|
+
return obj
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Deserialize a JSON string into an object.
|
222
|
+
#
|
223
|
+
# +obj+:: String or object to be deserialized.
|
224
|
+
# +obj_class+:: Class literal for deserialzied object, or string of class name.
|
225
|
+
def deserialize(obj, obj_class)
|
226
|
+
case obj_class.downcase
|
227
|
+
when 'str'
|
228
|
+
return obj.to_s
|
229
|
+
when 'int'
|
230
|
+
return obj.to_i
|
231
|
+
when 'float'
|
232
|
+
return obj.to_f
|
233
|
+
when 'bool'
|
234
|
+
return bool(obj)
|
235
|
+
when 'file'
|
236
|
+
# Bio::BaseSpace::File
|
237
|
+
instance = File.new
|
238
|
+
else
|
239
|
+
# models in BaseSpace
|
240
|
+
klass = Object.const_get(obj_class)
|
241
|
+
instance = klass.new
|
242
|
+
end
|
243
|
+
|
244
|
+
if $DEBUG
|
245
|
+
$stderr.puts " # ----- APIClient#deserialize ----- "
|
246
|
+
$stderr.puts " # caller: #{caller}"
|
247
|
+
$stderr.puts " # obj_class: #{obj_class}"
|
248
|
+
$stderr.puts " # obj: #{obj}" # JSON.pretty_generate(obj)
|
249
|
+
$stderr.puts " # "
|
250
|
+
end
|
251
|
+
|
252
|
+
instance.swagger_types.each do |attr, attr_type|
|
253
|
+
if obj.has_key?(attr) or obj.has_key?(attr.to_s)
|
254
|
+
if $DEBUG
|
255
|
+
$stderr.puts " # # ----- APIClient#deserialize/swagger_types ----- "
|
256
|
+
$stderr.puts " # # attr: #{attr}"
|
257
|
+
$stderr.puts " # # attr_type: #{attr_type}"
|
258
|
+
$stderr.puts " # # value: #{obj[attr]}"
|
259
|
+
$stderr.puts " # # "
|
260
|
+
end
|
261
|
+
value = obj[attr]
|
262
|
+
case attr_type.downcase
|
263
|
+
when 'str'
|
264
|
+
instance.set_attr(attr, value.to_s)
|
265
|
+
when 'int'
|
266
|
+
instance.set_attr(attr, value.to_i)
|
267
|
+
when 'float'
|
268
|
+
instance.set_attr(attr, value.to_f)
|
269
|
+
when 'datetime'
|
270
|
+
instance.set_attr(attr, DateTime.parse(value))
|
271
|
+
when 'bool'
|
272
|
+
instance.set_attr(attr, bool(value))
|
273
|
+
when /list</
|
274
|
+
sub_class = attr_type[/list<(.*)>/, 1]
|
275
|
+
sub_values = []
|
276
|
+
value.each do |sub_value|
|
277
|
+
sub_values << deserialize(sub_value, sub_class)
|
278
|
+
end
|
279
|
+
instance.set_attr(attr, sub_values)
|
280
|
+
when 'dict' # support for parsing dictionary
|
281
|
+
if $DEBUG
|
282
|
+
$stderr.puts " # # # ----- APIClient#deserialize/swagger_types/dict ----- "
|
283
|
+
$stderr.puts " # # # dict: #{value}"
|
284
|
+
$stderr.puts " # # # "
|
285
|
+
end
|
286
|
+
# [TODO] May need to convert value -> Hash (check in what format the value is passed)
|
287
|
+
instance.set_attr(attr, value)
|
288
|
+
else
|
289
|
+
if $DEBUG
|
290
|
+
# print "recursive call w/ " + attrType
|
291
|
+
$stderr.puts " # # # ----- APIClient#deserialize/swagger_types/recursive call ----- "
|
292
|
+
$stderr.puts " # # # attr: #{attr}"
|
293
|
+
$stderr.puts " # # # attr_type: #{attr_type}"
|
294
|
+
$stderr.puts " # # # value: #{value}"
|
295
|
+
$stderr.puts " # # # "
|
296
|
+
end
|
297
|
+
instance.set_attr(attr, deserialize(value, attr_type))
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
if $DEBUG
|
302
|
+
$stderr.puts " # # ----- APIClient#deserialize/instance ----- "
|
303
|
+
$stderr.puts " # # instance: #{instance.attributes.inspect}"
|
304
|
+
$stderr.puts " # # "
|
305
|
+
end
|
306
|
+
return instance
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
end # module BaseSpace
|
312
|
+
end # module Bio
|
313
|
+
|