Skip to content

Theo query service with Anya edits#6655

Draft
anna-parker wants to merge 23 commits into
mainfrom
anya-query-service
Draft

Theo query service with Anya edits#6655
anna-parker wants to merge 23 commits into
mainfrom
anya-query-service

Conversation

@anna-parker

@anna-parker anna-parker commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Basically #6645 but I tried to add a swaggerUI

One limitation of SwaggerUI (actually OpenAPI spec):

OpenAPI can define fixed enum options for each parameter, e.g. param B has [optionC, optionD], but Swagger UI does not dynamically filter param B’s dropdown based on param A’s selected value. Enums are static per parameter.

This means we cannot dynamically change e.g. the metadata or reference options available in swaggerUI when a user selects e.g. a different organism. Commonly this is either solved by adding a different endpoint for each case (i.e. organism) or by moving validation to the server (which we anyways do) and having less precise docs.

I believe the only way to do this is to add custom plugins/modifications, here I added an option to filter to a specific organism and update the allowed parameters.

Screenshot

image
GET|POST  /v1/aggregated                    ?organism=
GET|POST  /v1/metadata                       ?organism=

GET|POST  /v1/mutations                     ?organism=
GET|POST  /v1/aaMutations                   ?organism=
GET|POST  /v1/insertions                    ?organism=
GET|POST  /v1/aaInsertions                  ?organism=

GET|POST  /v1/alignedSequences              ?organism= [&segment=<name>] [&reference=<name>]
GET|POST  /v1/unalignedSequences            ?organism= [&segment=<name>] [&reference=<name>]
GET|POST  /v1/aaSequences                   ?organism= [&cds=<name>] [&reference=<name>]

GET       /v1/info                          ?organism=
GET       /v1/lineageDefinition             ?organism=&column=
GET       /v1/organisms                     (returns organism→segment/reference config)

organism is required and single-valued.

PR Checklist

  • All necessary documentation has been adapted.
  • The implemented feature is covered by appropriate, automated tests.
  • Any manual testing that has been done is documented (i.e. what exactly was tested?)

🚀 Preview: Add preview label to enable

theosanderson and others added 11 commits June 10, 2026 22:30
…f LAPIS

Adds a new single-deployment service (query-service/) that proxies
/{organism}/{path} to the corresponding loculus-lapis-service-{organism}.
For now it is a transparent passthrough; the point is to give us a
single hop where we can rewrite LAPIS responses in future iterations
without changing the website or LAPIS.

Wires the website (server-side lapisUrls), the lapis ingress, and the
public lapisUrls (used by the browser and CLI) through the new
service, so all external and internal LAPIS calls now go through it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The query-service is now the only LAPIS-facing surface. The old
`/{organism}/{path}` passthrough is removed.

API shape (see query-service/README.md):
  - Owned verbs under /v1/: aggregated, details, mutations, aaMutations,
    insertions, aaInsertions, alignedSequences[/segment],
    unalignedSequences[/segment], aaSequences/<protein>, info,
    lineageDefinition.
  - `?organism=` is required and single-valued.
  - Reserved control keywords: organism, format (-> dataFormat),
    download (-> downloadAsFile), fields, limit, offset, include,
    reference. Anything else is a metadata-column filter.
  - Implicit defaults applied centrally: versionStatus=LATEST_VERSION,
    isRevocation=false. Override with `include=revoked|older-versions|all`.
    Explicit version filters drop the defaults.

Helm:
  - Removed `lapisUrls` (per-organism map) from the website runtime config;
    replaced with a single `queryServiceUrl` plus an `organisms` list.
  - lapis-ingress is now a single rule that routes everything on the
    lapis hostname to query-service.

Website:
  - Renamed Zodios endpoints to /v1/<verb>; segment / proteinName are
    path components (Zodios needs unique paths per endpoint).
  - LapisClient now takes (queryServiceUrl, organism, schema) and adds
    `?organism=` to every call. Internal name unchanged to limit churn.
  - DownloadUrlGenerator builds /v1/... URLs and adds ?organism=.
  - Dropped manual versionStatus / isRevocation defaults from server-side
    callers (GroupPage, getSeqSetStatistics, getOrganismStatistics) — the
    query-service applies them.
  - /loculus-info now exposes hosts.queryService instead of hosts.lapis.

CLI:
  - Migrated to /v1/ paths with ?organism=.
  - get_lapis_url() retained as a thin wrapper that returns the
    query-service base URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… POSTs

Adds the missing pieces to keep the prior search-page UX (where users
can clear the version-status / revocation hidden-field defaults to see
all versions) working against the new query-service defaults.

- lapisApi.ts: every /v1/ endpoint now accepts an optional `include`
  query parameter.
- serviceHooks.lapisClientHooks: takes an `options.include` and threads
  it onto every request as a query string. The search UI passes
  `'all'`; autocomplete and detail views leave it unset so query-service
  defaults still apply there.
- SearchFullUI / serversideSearch / DownloadUrlGenerator: pass
  `include=all`, since the search page manages its own version
  defaults via hiddenFieldValues.
- LapisClient.getAllSequenceEntryHistoryForAccession: passes
  `include=all` (version history needs every version + revocation).
- query-service:
  - reads `include=` from the query string for POSTs too (was only
    looking in the body), so the website's `?include=all` is honoured.
  - parses `application/x-www-form-urlencoded` bodies for the long-query
    download path that submits an HTML form. Uses `getlist` so repeated
    keys (`fields=a&fields=b&fields=c`) are preserved as a list, not
    collapsed to the first value.
- Adds python-multipart to requirements (Starlette's form parser
  dependency).
- Updates DownloadDialog.spec.tsx assertions for the new
  `?organism=ebola&include=all&...` URL prefix.
- Fixes one stale `/sample/details` reference in
  download.dependent.spec.ts.

Integration suite: 98/98 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add .github/workflows/query-service-image.yml so the integration
  tests can pull commit-tagged images of the query-service. Mirrors
  preprocessing-dummy-image.yml: hash-based caching, multi-tag
  pushes, ARM build on main.
- Run prettier --write across files touched by the migration.
- Restore the versionStatus / isRevocation regex segments to the
  DownloadDialog spec assertions that exercise hiddenFieldValues —
  those filters _are_ sent in that flow (the test passes them
  explicitly), and the implicit defaults stay opt-out via include=all.
- Update vitest.setup.ts MSW mocks to point at the new sequence
  paths: /v1/alignedSequences[/segment], /v1/unalignedSequences[/segment].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e-all toggle

Following up on the previous commit so the website stops shipping the
versionStatus / isRevocation hidden defaults that the query-service is
already applying:

- Remove the `hiddenFieldValues` containing `versionStatus=LATEST_VERSION`
  and `isRevocation=false` from the search and submission/released pages.
  The query-service applies those defaults centrally — no need to also
  send them on the wire from the website.
- Drop the blanket `?include=all` from `lapisClientHooks` /
  `serversideSearch` / `DownloadUrlGenerator`. Default search now relies
  on query-service's defaults (latest non-revoked).
- Add an explicit "Include older versions and revocations" checkbox at
  the top of the search form. It writes `?include=all` into the URL,
  which the website then forwards as the `include=` query param. Toggle
  off and the URL drops the param so defaults reapply.
- Update the override-hidden-fields integration test to flip the new
  toggle instead of clearing the (no longer present) hidden fields.
- Replace the "hidden field values are kept in URL params" unit test
  with one that asserts the new `include=` toggle round-trips through
  the URL.
- Bump query-service CPU request/limit a touch (200m / 2 cores).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… include=all

- SearchFullUI: stabilise the empty `hiddenFieldValues` default with
  `useMemo`. The previous `??= {}` reassigned a fresh object every
  render, which destabilised the `useMemo` chain feeding the
  search-results `useEffect` and caused it to refire — the user observed
  this as an infinite loop of /v1/aggregated requests on the search page.
- /[organism]/submission/[groupId]/released: default `?include=all` so
  submitters see every version they've released (including revocations
  they've just made). The `mySequencesPage` route helper builds the
  link with that param and the page itself injects it into
  `initialQueryDict` for direct navigation.
… state

The React URL-syncing hook overwrites SSR-injected state with whatever
is actually in window.location on hydration, so injecting include=all
into initialQueryDict alone gets clobbered. Redirect server-side instead
so the URL itself is the source of truth, and hydration sees include=all.
…do /released redirect

- The 'override hidden fields' test was specifically exercising the
  removed clear-the-hidden-default mechanism. The replacement coverage
  is in search.dependent.spec.ts ('include-all toggle puts include=all
  in the URL'); the autocomplete-timeout flake on the deleted test was
  not adding signal.
- Reverting the server-side redirect to ?include=all on /released:
  some tests (e.g. file-sharing 'bulk revise 2 seqs with files') do
  page.goto(page.url() + '?column_submissionId=true') after navigating
  to /released, and the redirect made page.url() already carry an
  ?include=all so the appended ?column_... corrupted the URL into
  ?include=all?column_submissionId=true and query-service rejected the
  malformed include= value with 400 (which then tripped the
  console-warnings fixture).
  The link helper (routes.mySequencesPage) still adds ?include=all so
  the in-page 'released sequences' link gives submitters the
  see-everything view they need; tests that navigate directly retain
  default behaviour and can append params with ? safely.
The new query-service exposes /v1/aggregated rather than
/{organism}/sample/aggregated, so multi-field-search interceptors were
matching nothing and observing undefined status.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@anna-parker anna-parker changed the title Anya query service Theo query service with Anya edits Jun 10, 2026
@claude claude Bot added website Tasks related to the web application deployment Code changes targetting the deployment infrastructure labels Jun 10, 2026
@anna-parker anna-parker added the preview Triggers a deployment to argocd label Jun 10, 2026
@anna-parker anna-parker removed the preview Triggers a deployment to argocd label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deployment Code changes targetting the deployment infrastructure website Tasks related to the web application

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants