Module: OpenBEL::Helpers

Included in:
Routes::Datasets, Routes::Nanopubs
Defined in:
app/openbel/api/helpers/base.rb,
app/openbel/api/helpers/pager.rb,
app/openbel/api/helpers/filters.rb,
app/openbel/api/helpers/nanopub.rb,
app/openbel/api/helpers/translators.rb,
lib/openbel/api/helpers/uuid_generator.rb,
lib/openbel/api/helpers/dependency_graph.rb

Defined Under Namespace

Modules: Translators, UUIDGenerator Classes: DependencyGraph, Pager

Constant Summary collapse

DEFAULT_CONTENT_TYPE =
'application/hal+json'
DEFAULT_CONTENT_TYPE_ID =
:hal

Instance Method Summary collapse

Instance Method Details

#incomplete_filters(filters) ⇒ Array<Hash>

Retrieve the filters that do not provide category, name, and value keys.

The parsed, incomplete filters will contain an :error key that provides an error message intended for the user.

Parameters:

  • filters (Array<Hash>)

    an array of filter hashes

Returns:

  • (Array<Hash>)

    an array of incomplete filter hashes that contain a human-readable error at the :error key



33
34
35
36
37
38
39
40
41
42
43
# File 'app/openbel/api/helpers/filters.rb', line 33

def incomplete_filters(filters)
  filters.select { |filter|
    ['category', 'name', 'value'].any? { |f| !filter.include? f }
  }.map { |incomplete_filter|
    category, name, value = incomplete_filter.values_at('category', 'name', 'value')
    error = "      Incomplete filter, category:\"\#{category}\", name:\"\#{name}\", and value:\"\#{value}\".\n    MSG\n    incomplete_filter.merge(:error => error)\n  }\nend\n".gsub(/^\s+/, '').strip

#invalid_fts_filters(filters) ⇒ Array<Hash>

Retrieve the filters that represent invalid full-text search values.

The parsed, invalid full-text search filters will contain an :error key that provides an error message intended for the user.

Parameters:

  • filters (Array<Hash>)

    an array of filter hashes

Returns:

  • (Array<Hash>)

    an array of invalid full-text search filter hashes that contain a human-readable error at the :error key



54
55
56
57
58
59
60
61
62
63
64
# File 'app/openbel/api/helpers/filters.rb', line 54

def invalid_fts_filters(filters)
  filters.select { |filter|
    category, name, value = filter.values_at('category', 'name', 'value')
    category == 'fts' && name == 'search' && value.to_s.length <= 1
  }.map { |invalid_fts_filter|
    error = "      Full-text search filter values must be larger than one.\n    MSG\n    invalid_fts_filter.merge(:error => error)\n  }\nend\n".gsub(/^\s+/, '').strip

#parse_filters(filter_query_params) ⇒ Array<Array<Hash>, Array<String>] the first index holds the valid, ...

Parse filter query parameters and partition into an Array. The first index will contain the valid filters and the second index will contain the invalid filters.

Parameters:

  • filter_query_params (Array<String>)

    an array of filter strings encoded in JSON

Returns:

  • (Array<Array<Hash>, Array<String>] the first index holds the valid, filter {Hash hashes}; the second index holds the invalid, filter {String strings})

    Array<Array<Hash>, Array<String>] the first index holds the valid, filter hashes; the second index holds the invalid, filter strings



13
14
15
16
17
18
19
20
21
22
23
# File 'app/openbel/api/helpers/filters.rb', line 13

def parse_filters(filter_query_params)
  filter_query_params.map { |filter_string|
    begin
      MultiJson.load filter_string
    rescue MultiJson::ParseError => ex
      "#{ex} (filter: #{filter_string})"
    end
  }.partition { |filter|
    filter.is_a?(Hash)
  }
end

#render_nanopub_collection(name, page_results, start, size, filters, filtered_total, collection_total, nanopub_api) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'app/openbel/api/helpers/nanopub.rb', line 8

def render_nanopub_collection(
  name, page_results, start, size, filters,
  filtered_total, collection_total, nanopub_api
)
  # see if the user requested a BEL translator (Accept header or ?format)
  translator        = Translators.requested_translator(request, params)
  translator_plugin = Translators.requested_translator_plugin(request, params)

  halt 404 unless page_results[:cursor].has_next?

  # Serialize to HAL if they [Accept]ed it, specified it as ?format, or
  # no translator was found to match request.
  if wants_default? || !translator
    facets   = page_results[:facets]
    pager    = Pager.new(start, size, filtered_total)
    nanopub = page_results[:cursor].map { |item|
                 item.delete('facets')
                 item
               }.to_a

    options = {
      :facets   => facets,
      :start    => start,
      :size     => size,
      :filters  => filters,
      :metadata => {
        :collection_paging => {
          :total                  => collection_total,
          :total_filtered         => pager.total_size,
          :total_pages            => pager.total_pages,
          :current_page           => pager.current_page,
          :current_page_size      => nanopub.size,
        }
      }
    }

    # pager links
    options[:previous_page] = pager.previous_page
    options[:next_page]     = pager.next_page

    render_collection(nanopub, :nanopub, options)
  else
    extension = translator_plugin.file_extensions.first

    response.headers['Content-Type'] = translator_plugin.media_types.first
    status 200
    attachment "#{name}.#{extension}"
    stream :keep_open do |response|
      cursor             = page_results[:cursor]
      dataset_nanopub = cursor.lazy.map { |nanopub|
        nanopub.delete('facets')
        nanopub.delete('_id')
        nanopub = BEL::Nanopub::Nanopub.create(BEL.keys_to_symbols(nanopub))
        nanopub
      }

      translator.write(
        dataset_nanopub, response,
        :annotation_reference_map => nanopub_api.find_all_annotation_references,
        :namespace_reference_map  => nanopub_api.find_all_namespace_references
      )
    end
  end
end

#validate_filters!Object

Validate the requested filter query strings. If all filters are valid then return them as hashes, otherwise halt 400 Bad Request and return JSON error response.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/openbel/api/helpers/filters.rb', line 69

def validate_filters!
  filter_query_params = CGI::parse(env["QUERY_STRING"])['filter']
  valid_filters, invalid_filters = parse_filters(filter_query_params)

  invalid_filters |= incomplete_filters(valid_filters)
  invalid_filters |= invalid_fts_filters(valid_filters)

  return valid_filters if invalid_filters.empty?

  halt(400, { 'Content-Type' => 'application/json' }, render_json({
    :status => 400,
    :msg => "Bad Request",
    :detail =>
      invalid_filters.
      map { |invalid_filter|
        if invalid_filter.is_a?(Hash) && invalid_filter[:error]
          invalid_filter[:error]
        else
          invalid_filter
        end
      }.
      map(&:to_s)
  }))
end

#wants_default?Boolean

Returns:

  • (Boolean)


7
8
9
10
11
12
13
14
15
# File 'app/openbel/api/helpers/base.rb', line 7

def wants_default?
  if params[:format]
    return params[:format] == DEFAULT_CONTENT_TYPE
  end

  request.accept.any? { |accept_entry|
    accept_entry.to_s == DEFAULT_CONTENT_TYPE
  }
end