openbel-api 1.1.1-java → 1.2.0-java
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/VERSION +1 -1
- data/app/openbel/api/resources/nanopub_transform.rb +2 -0
- data/app/openbel/api/routes/nanopubs.rb +251 -14
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afc3b945f3e3718c2be3732855cb00d83110c84a
|
4
|
+
data.tar.gz: 1d35a94f8f9799a6deaaa5b07ce3a30a44f4bb17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4646ef99f095e1235c249dca5f91e45e7db0c8979d24f3e5d0d0ab085b0cd2719c03fd24ad267aa1f8844c2d3e3c3eb2cd87da07180e0b36adf01ef09d81beef
|
7
|
+
data.tar.gz: ac9109a8b4594fd919bd73e40cdb75db784bf69ad32bb9526cc41205dc69a1acc4c0126a33bc434c8933bf916ca284d2f00db5d2e47a457dccd56ebd2fe7600e
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,12 @@ All notable changes to openbel-api will be documented in this file. The curated
|
|
3
3
|
|
4
4
|
This project adheres to [Semantic Versioning][Semantic Versioning].
|
5
5
|
|
6
|
+
|
7
|
+
## [1.2.0][1.2.0] - 2017-01-22
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- strict=yes query param on POST /api/nanopub will result in a 422 if the BEL statement or Annotations are bad
|
11
|
+
|
6
12
|
## [1.1.0][1.1.0] - 2017-01-21
|
7
13
|
|
8
14
|
### Added
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
@@ -94,6 +94,8 @@ module OpenBEL
|
|
94
94
|
identifier = annotation_value.identifier.first.to_s
|
95
95
|
value_label = annotation_value.pref_label.first.to_s
|
96
96
|
if annotation_value
|
97
|
+
identifier = annotation_value.identifier.first.to_s
|
98
|
+
value_label = annotation_value.pref_label.first.to_s
|
97
99
|
{
|
98
100
|
:name => annotation_label,
|
99
101
|
:value => value_label,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'bel'
|
2
|
+
require 'bel_parser'
|
2
3
|
require 'cgi'
|
3
4
|
require 'openbel/api/nanopub/mongo'
|
4
5
|
require 'openbel/api/nanopub/facet_filter'
|
@@ -14,10 +15,14 @@ module OpenBEL
|
|
14
15
|
include OpenBEL::Nanopub::FacetFilter
|
15
16
|
include OpenBEL::Resource::Nanopub
|
16
17
|
include OpenBEL::Helpers
|
18
|
+
include BELParser::Parsers
|
17
19
|
|
18
20
|
def initialize(app)
|
19
21
|
super
|
20
22
|
|
23
|
+
bel_version = OpenBEL::Settings[:bel][:version]
|
24
|
+
@spec = BELParser::Language.specification(bel_version)
|
25
|
+
|
21
26
|
mongo = OpenBEL::Settings[:nanopub_store][:mongo]
|
22
27
|
@api = OpenBEL::Nanopub::Nanopub.new(mongo)
|
23
28
|
|
@@ -50,6 +55,20 @@ module OpenBEL
|
|
50
55
|
}
|
51
56
|
}
|
52
57
|
}
|
58
|
+
|
59
|
+
@supported_namespaces = Hash[
|
60
|
+
@namespaces.each.map { |ns|
|
61
|
+
prefix = ns.prefix.first.upcase
|
62
|
+
|
63
|
+
[
|
64
|
+
prefix,
|
65
|
+
BELParser::Expression::Model::Namespace.new(
|
66
|
+
prefix,
|
67
|
+
ns.uri
|
68
|
+
)
|
69
|
+
]
|
70
|
+
}
|
71
|
+
]
|
53
72
|
end
|
54
73
|
|
55
74
|
configure :development do |config|
|
@@ -120,6 +139,165 @@ module OpenBEL
|
|
120
139
|
new_hash
|
121
140
|
end
|
122
141
|
end
|
142
|
+
|
143
|
+
def validate_experiment_context(experiment_context)
|
144
|
+
valid_annotations = []
|
145
|
+
invalid_annotations = []
|
146
|
+
experiment_context.values.each do |annotation|
|
147
|
+
name, value = annotation.values_at(:name, :value)
|
148
|
+
found_annotation = @annotations.find(name).first
|
149
|
+
|
150
|
+
if found_annotation
|
151
|
+
if found_annotation.find(value).first == nil
|
152
|
+
# structured annotations, without a match, is invalid
|
153
|
+
invalid_annotations << annotation
|
154
|
+
else
|
155
|
+
# structured annotations, with a match, is invalid
|
156
|
+
valid_annotations << annotation
|
157
|
+
end
|
158
|
+
else
|
159
|
+
# free annotations considered valid
|
160
|
+
valid_annotations << annotation
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
[
|
165
|
+
invalid_annotations.empty? ? :valid : :invalid,
|
166
|
+
{
|
167
|
+
:valid => invalid_annotations.empty?,
|
168
|
+
:valid_annotations => valid_annotations,
|
169
|
+
:invalid_annotations => invalid_annotations,
|
170
|
+
:message =>
|
171
|
+
invalid_annotations
|
172
|
+
.map { |annotation|
|
173
|
+
name, value = annotation.values_at(:name, :value)
|
174
|
+
%Q{The value "#{value}" was not found in annotation "#{name}".}
|
175
|
+
}
|
176
|
+
.join("\n")
|
177
|
+
}
|
178
|
+
]
|
179
|
+
end
|
180
|
+
|
181
|
+
def validate_statement(bel)
|
182
|
+
filter =
|
183
|
+
BELParser::ASTFilter.new(
|
184
|
+
BELParser::ASTGenerator.new("#{bel}\n"),
|
185
|
+
:simple_statement,
|
186
|
+
:observed_term,
|
187
|
+
:nested_statement
|
188
|
+
)
|
189
|
+
_, _, ast = filter.each.first
|
190
|
+
|
191
|
+
if ast.nil? || ast.empty?
|
192
|
+
return [
|
193
|
+
:syntax_invalid,
|
194
|
+
{
|
195
|
+
valid_syntax: false,
|
196
|
+
valid_semantics: false,
|
197
|
+
message: 'Invalid syntax.',
|
198
|
+
warnings: [],
|
199
|
+
term_signatures: []
|
200
|
+
}
|
201
|
+
]
|
202
|
+
end
|
203
|
+
|
204
|
+
urir = BELParser::Resource.default_uri_reader
|
205
|
+
urlr = BELParser::Resource.default_url_reader
|
206
|
+
validator = BELParser::Language::ExpressionValidator.new(@spec, @supported_namespaces, urir, urlr)
|
207
|
+
message = ''
|
208
|
+
terms = ast.first.traverse.select { |node| node.type == :term }.to_a
|
209
|
+
|
210
|
+
semantics_functions =
|
211
|
+
BELParser::Language::Semantics.semantics_functions.reject { |fun|
|
212
|
+
fun == BELParser::Language::Semantics::SignatureMapping
|
213
|
+
}
|
214
|
+
|
215
|
+
result = validator.validate(ast.first)
|
216
|
+
syntax_errors = result.syntax_results.map(&:to_s)
|
217
|
+
|
218
|
+
semantic_warnings =
|
219
|
+
ast
|
220
|
+
.first
|
221
|
+
.traverse
|
222
|
+
.flat_map { |node|
|
223
|
+
semantics_functions.flat_map { |func|
|
224
|
+
func.map(node, @spec, @supported_namespaces)
|
225
|
+
}
|
226
|
+
}
|
227
|
+
.compact
|
228
|
+
|
229
|
+
if syntax_errors.empty? && semantic_warnings.empty?
|
230
|
+
valid = true
|
231
|
+
else
|
232
|
+
valid = false
|
233
|
+
message = ''
|
234
|
+
message +=
|
235
|
+
syntax_errors.reduce('') { |msg, error|
|
236
|
+
msg << "#{error}\n"
|
237
|
+
}
|
238
|
+
message +=
|
239
|
+
semantic_warnings.reduce('') { |msg, warning|
|
240
|
+
msg << "#{warning}\n"
|
241
|
+
}
|
242
|
+
message << "\n"
|
243
|
+
end
|
244
|
+
|
245
|
+
term_semantics =
|
246
|
+
terms.map { |term|
|
247
|
+
term_result = validator.validate(term)
|
248
|
+
valid &= term_result.valid_semantics?
|
249
|
+
bel_term = serialize(term)
|
250
|
+
|
251
|
+
unless valid
|
252
|
+
message << "Term: #{bel_term}\n"
|
253
|
+
term_result.invalid_signature_mappings.map { |m|
|
254
|
+
message << " #{m}\n"
|
255
|
+
}
|
256
|
+
message << "\n"
|
257
|
+
end
|
258
|
+
|
259
|
+
{
|
260
|
+
term: bel_term,
|
261
|
+
valid: term_result.valid_semantics?,
|
262
|
+
errors: term_result.syntax_results.map(&:to_s),
|
263
|
+
valid_signatures: term_result.valid_signature_mappings.map(&:to_s),
|
264
|
+
invalid_signatures: term_result.invalid_signature_mappings.map(&:to_s)
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
[
|
269
|
+
valid ? :valid : :semantics_invalid,
|
270
|
+
{
|
271
|
+
expression: bel,
|
272
|
+
valid_syntax: true,
|
273
|
+
valid_semantics: valid,
|
274
|
+
message: valid ? 'Valid semantics' : message,
|
275
|
+
errors: syntax_errors,
|
276
|
+
warnings: semantic_warnings.map(&:to_s),
|
277
|
+
term_signatures: term_semantics
|
278
|
+
}
|
279
|
+
]
|
280
|
+
end
|
281
|
+
|
282
|
+
def validate_nanopub!(bel_statement, experiment_context)
|
283
|
+
stmt_result, stmt_validation = validate_statement(bel_statement)
|
284
|
+
expctx_result, expctx_validation = validate_experiment_context(experiment_context)
|
285
|
+
|
286
|
+
return nil if stmt_result == :valid && expctx_result == :valid
|
287
|
+
|
288
|
+
halt(
|
289
|
+
422,
|
290
|
+
{'Content-Type' => 'application/json'},
|
291
|
+
render_json(
|
292
|
+
{
|
293
|
+
:nanopub_validation => {
|
294
|
+
:bel_statement_validation => stmt_validation,
|
295
|
+
:experiment_context_validation => expctx_validation
|
296
|
+
}
|
297
|
+
}
|
298
|
+
)
|
299
|
+
)
|
300
|
+
end
|
123
301
|
end
|
124
302
|
|
125
303
|
options '/api/nanopubs' do
|
@@ -135,8 +313,10 @@ module OpenBEL
|
|
135
313
|
post '/api/nanopubs' do
|
136
314
|
# Validate BNJ.
|
137
315
|
validate_media_type! "application/json"
|
316
|
+
|
317
|
+
strict = as_bool(params[:strict]) || false
|
318
|
+
|
138
319
|
nanopub_obj = read_json
|
139
|
-
# STDERR.puts "DBG: nanopub_obj Variable config is #{nanopub_obj.inspect}"
|
140
320
|
schema_validation = validate_schema(keys_to_s_deep(nanopub_obj), :nanopub)
|
141
321
|
unless schema_validation[0]
|
142
322
|
halt(
|
@@ -146,22 +326,46 @@ module OpenBEL
|
|
146
326
|
)
|
147
327
|
end
|
148
328
|
|
149
|
-
nanopub_hash
|
150
|
-
nanopub_hash[:references]
|
329
|
+
nanopub_hash = nanopub_obj[:nanopub]
|
330
|
+
if nanopub_hash[:references]
|
331
|
+
nanopub_hash[:references] = {
|
332
|
+
:annotations => nanopub_hash[:references][:annotations].map { |anno|
|
333
|
+
{
|
334
|
+
:keyword => anno[:keyword],
|
335
|
+
:type => :uri,
|
336
|
+
:domain => anno[:uri]
|
337
|
+
}
|
338
|
+
},
|
339
|
+
:namespaces => nanopub_hash[:references][:namespaces].map { |ns|
|
340
|
+
{
|
341
|
+
:keyword => ns[:keyword],
|
342
|
+
:type => :uri,
|
343
|
+
:domain => ns[:uri]
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
else
|
348
|
+
nanopub_hash[:references] = @default_references
|
349
|
+
end
|
350
|
+
|
351
|
+
original_bel_statement = nanopub_hash[:bel_statement]
|
151
352
|
|
152
|
-
|
153
|
-
|
353
|
+
begin
|
354
|
+
nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
|
355
|
+
rescue ArgumentError
|
356
|
+
nanopub_hash[:bel_statement] = nil
|
357
|
+
nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
|
358
|
+
end
|
154
359
|
|
155
360
|
# Standardize annotations.
|
156
361
|
@annotation_transform.transform_nanopub!(nanopub, base_url)
|
157
362
|
|
158
|
-
#
|
159
|
-
|
160
|
-
hash = nanopub.to_h
|
161
|
-
hash[:bel_statement] = hash.fetch(:bel_statement, nil).to_s
|
162
|
-
|
163
|
-
# STDERR.puts "DBG: Variable config is #{hash.inspect}"
|
363
|
+
# Validate nanopub when strict is enabled.
|
364
|
+
validate_nanopub!(original_bel_statement, nanopub.experiment_context) if strict
|
164
365
|
|
366
|
+
facets = map_nanopub_facets(nanopub)
|
367
|
+
hash = nanopub.to_h
|
368
|
+
hash[:bel_statement] = (hash[:bel_statement] || original_bel_statement).to_s
|
165
369
|
hash[:facets] = facets
|
166
370
|
_id = @api.create_nanopub(hash)
|
167
371
|
|
@@ -235,6 +439,8 @@ module OpenBEL
|
|
235
439
|
|
236
440
|
validate_media_type! "application/json"
|
237
441
|
|
442
|
+
strict = as_bool(params[:strict]) || false
|
443
|
+
|
238
444
|
ev = @api.find_nanopub_by_id(object_id)
|
239
445
|
halt 404 unless ev
|
240
446
|
|
@@ -248,14 +454,45 @@ module OpenBEL
|
|
248
454
|
)
|
249
455
|
end
|
250
456
|
|
251
|
-
nanopub_hash
|
252
|
-
nanopub_hash[:references]
|
457
|
+
nanopub_hash = nanopub_obj[:nanopub]
|
458
|
+
if nanopub_hash[:references]
|
459
|
+
nanopub_hash[:references] = {
|
460
|
+
:annotations => nanopub_hash[:references][:annotations].map { |anno|
|
461
|
+
{
|
462
|
+
:keyword => anno[:keyword],
|
463
|
+
:type => :uri,
|
464
|
+
:domain => anno[:uri]
|
465
|
+
}
|
466
|
+
},
|
467
|
+
:namespaces => nanopub_hash[:references][:namespaces].map { |ns|
|
468
|
+
{
|
469
|
+
:keyword => ns[:keyword],
|
470
|
+
:type => :uri,
|
471
|
+
:domain => ns[:uri]
|
472
|
+
}
|
473
|
+
}
|
474
|
+
}
|
475
|
+
else
|
476
|
+
nanopub_hash[:references] = @default_references
|
477
|
+
end
|
478
|
+
|
479
|
+
original_bel_statement = nanopub_hash[:bel_statement]
|
480
|
+
|
481
|
+
begin
|
482
|
+
nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
|
483
|
+
rescue ArgumentError
|
484
|
+
nanopub_hash[:bel_statement] = nil
|
485
|
+
nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
|
486
|
+
end
|
253
487
|
|
254
488
|
# transformation
|
255
|
-
nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
|
256
489
|
@annotation_transform.transform_nanopub!(nanopub, base_url)
|
257
490
|
|
491
|
+
# Validate nanopub when strict is enabled.
|
492
|
+
validate_nanopub!(original_bel_statement, nanopub.experiment_context) if strict
|
493
|
+
|
258
494
|
facets = map_nanopub_facets(nanopub)
|
495
|
+
hash[:bel_statement] = (hash[:bel_statement] || original_bel_statement).to_s
|
259
496
|
nanopub = nanopub.to_h
|
260
497
|
nanopub[:bel_statement] = nanopub.fetch(:bel_statement, nil).to_s
|
261
498
|
nanopub[:facets] = facets
|