Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add select parameter with options from remote resources #17087

Merged
merged 10 commits into from
Feb 14, 2024

Conversation

mvdbeek
Copy link
Member

@mvdbeek mvdbeek commented Nov 27, 2023

Updating regular tool data tables for frequently changing data is a little tricky, and it was requested that we allow loading options dynamically from a URL. The eventual goals of this work is to enable exploring resources with great APIs (NCBI datasets is a good example) from within Galaxy tools.

Includes a little mini-language for manipulating arbitrary JSON responses using ECMAScript expressions.

From the schema:

from_url

The following example demonstrates getting options from a third-party server
with server side requests.

<param name="url_param_value" type="select">
    <options from_url="https://usegalaxy.org/api/genomes">
    </options>
</param>

Here a GET request is made to https://usegalaxy.org/api/genomes, which returns
an array of arrays, such as

[
    ["unspecified (?)", "?"],
    ["A. ceylanicum Mar. 2014 (WS243/Acey_2013.11.30.genDNA/ancCey1) (ancCey1)", "ancCey1"],
    ...
]

Each inner array is a user-selectable option, where the first item in the inner array
is the name of the option (as shown in the select field in the user interface), and
the second option is the value that is passed on to the tool. An optional third
element can be added to the inner array which corresponds to the selected state.
If the third item is true then this particular option is pre-selected.

A more complicated example is shown below, where a POST request is made with a templated
request header and body. The upstream response is then also transformed using an ecma 5.1
expression:

<param name="url_param_value_header_and_body" type="select">
    <options from_url="https://postman-echo.com/post" request_method="POST">
        <!-- Example for accessing user secrets via extra preferences -->
        <request_headers type="json">
            {"x-api-key": "${__user__.extra_preferences.fake_api_key if $__user__ else "anon"}"}
        </request_headers>
        <request_body type="json">
            {"name": "value"}
        </request_body>
        <!-- https://postman-echo.com/post echos values sent to it, so here we list the response headers -->
        <postprocess_expression type="ecma5.1"><![CDATA[${
            return Object.keys(inputs.headers).map((header) => [header, header])
        }]]></postprocess_expression>
    </options>
</param>

The header and body templating mechanism can be used to access protected resources,
and the postprocess_expression can be used to transform arbitrary JSON responses
to arrays of name and value, or arrays of name, value and selected.

For an example tool see select_from_url.xml.

How to test the changes?

(Select all options that apply)

  • I've included appropriate automated tests.
  • This is a refactoring of components with existing test coverage.
  • Instructions for manual testing are as follows:
    1. [add testing steps and prerequisites here if you didn't write automated tests covering all your changes]

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

@mvdbeek mvdbeek changed the title Add <options from_url="https://example.com"></options> Add select parameter with options from remote resources Nov 27, 2023
@jmchilton
Copy link
Member

Nifty!

@mvdbeek mvdbeek marked this pull request as ready for review November 28, 2023 16:50
@github-actions github-actions bot added this to the 23.2 milestone Nov 28, 2023
@mvdbeek mvdbeek force-pushed the from_url_option branch 2 times, most recently from 86545e5 to 5390ef1 Compare November 29, 2023 08:46
@mvdbeek mvdbeek modified the milestones: 23.2, 24.0 Dec 19, 2023
@@ -4442,6 +4448,7 @@ used to generate dynamic options.
<xs:element name="filter" type="Filter" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="column" type="Column" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="validator" type="Validator" minOccurs="0" maxOccurs="1"/>
<xs:element name="postprocess_expression" type="Expression" minOccurs="0" maxOccurs="1"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe link the test tool from here?

Maybe a linter checking that postprocess_expression only appears for from_url could be nice. But this would only make sense with the big linter PR merged.

test/functional/tools/select_from_url.xml Show resolved Hide resolved
test/functional/tools/select_from_url.xml Show resolved Hide resolved
@@ -766,6 +774,39 @@ def get_field_by_name_for_value(self, field_name, value, trans, other_values):
return rval

def get_options(self, trans, other_values):
def to_triple(values):
if len(values) == 2:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we cover empty values or values of length 1? Or non-dict values?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example for when that would be useful ? Keep in mind that the expression is evaluated on the request's response

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't know what the response is, or? Could be just a list of length 1, an empty list, or a string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is that you can transform anything that is returned, so IMO that is where the complexity should go, not here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. That's fine with me. Could you add this to the docs for from_url, i.e. that the code expects an array of length 2 or 3 in the response, or the response being transformed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely, there's some expansion needed.

Updating regular tool data tables for frequently changing data is a
little tricky, and it was requested that we allow loading options
dynamically from a URL. The eventual goals of this work is to enable
exploring resources with great APIs (NCBI datasets is a good exmaple)
from within Galaxy tools.

This doesn't do any of that yet ... it's just a simple URL one can
query with a GET request, and the data there must be in the format
["name", "value", True|False].

Following steps:
  - [x] allow templating (Cheetah ? JS?)
  - [x] allow post-processing to extract name-value pairs
    - jq-like syntax ?
    - [x] JS expression ?
  - add pagination (requires work on vue-multiselect)
  - add request caching

Some potential issues:
  - Slow server responses: use async library and cancel request after N
    seconds ?
  - Large respons ... stream response and cancel after configurable max
    response size ?
Context are the user context values, we could extend that as needed.
@mvdbeek mvdbeek force-pushed the from_url_option branch 2 times, most recently from aa87988 to 204dee1 Compare February 13, 2024 11:31
@mvdbeek mvdbeek requested a review from a team February 13, 2024 14:10
@mvdbeek
Copy link
Member Author

mvdbeek commented Feb 14, 2024

@bernt-matthias what do you think, I've added some documentation to the xsd (also in the PR description)

Copy link
Contributor

@bernt-matthias bernt-matthias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants