openbel-api 1.1.1-java → 1.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 121260d75016a848b38d53fd21034b6a3d487401
4
- data.tar.gz: 23ebb2c2df88257a76db162dd0fbf05269977237
3
+ metadata.gz: afc3b945f3e3718c2be3732855cb00d83110c84a
4
+ data.tar.gz: 1d35a94f8f9799a6deaaa5b07ce3a30a44f4bb17
5
5
  SHA512:
6
- metadata.gz: 07f857a7ae76c0635e722760896aa0b00bfa0d6d3b85cbfaf237bc7ef437d207cbab0b70002a74a620295d0c57de8664d9bf0e657dfff50449e9ea8c1c7053a8
7
- data.tar.gz: 9db88ef3ef4d24699ed6ff66c060cfca5edf24ae4f591884512d9d5fc7a02223e88f0867aa4692934c4048c82166a6bda83adef66baa28d15fb5bc15954e4cf5
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
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 = nanopub_obj[:nanopub]
150
- nanopub_hash[:references] ||= @default_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
- nanopub = ::BEL::Nanopub::Nanopub.create(nanopub_hash)
153
- # STDERR.puts "DBG: nanopub Variable config is #{nanopub.inspect}"
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
- # Build facets.
159
- facets = map_nanopub_facets(nanopub)
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 = nanopub_obj[:nanopub]
252
- nanopub_hash[:references] ||= @default_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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openbel-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: java
6
6
  authors:
7
7
  - Anthony Bargnesi