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 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