Repository navigation
feat: add search query endpoint with request examples - #34
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an OpenAPI definition for a new beta search endpoint modeled after Microsoft Graph Search, including request/response schemas and multiple example payloads to document common search scenarios.
Changes:
- Introduces
POST /v1beta1/search/querywith detailed description and request/response examples. - Adds search-related schemas (
searchRequest,searchQuery,searchResponse, aggregation/bucket schemas) undercomponents/schemas. - Wires the new endpoint to the new schemas via
$refto keep the spec structured.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@dschmidt Since the search endpoint returns plain drive items I'm wondering how we would handle the additional information the results are currently being enriched with (see https://github.com/opencloud-eu/opencloud/blob/main/services/webdav/pkg/service/v0/search.go#L150-L263 for the current state). Things like the tags could be derived from the arbitrary metadata (which currently isn't exposed afaict), but do you have an idea how we would handle the |
|
Very good questions, thanks! I assume
Although this introduces user specific data to the driveItem, We could introduce a custom prop like |
|
The thumbnails relationship is already in the spec, it might still need implementation tho 😅 |
|
Aha, I just realized the follow endpoints map to setting the favorite state... so just @libre.graph.following or @libre.graph.user.following on the driveItem? If you agree, I can send another PR for that, to keep this one scoped |
|
#37 👀 |
|
What's also potentially missing: short permissions/allowed actions without loading all shares Not sure how we want to do that? Thoughts? |
we introduced @libre.graph.permissions.roles.allowedValues and @libre.graph.permissions.actions.allowedValues to let the web ui build the sharing dialog. see https://docs.opencloud.eu/docs/dev/server/apis/http/graph/permissions for what that looks like or just monitor your browsers network tab when opening the sharing dialog in the web ui. Let me know if that covers what you have in mind |
Adds an optional, `$select`-gated instance annotation on `driveItem` that carries the list of libre.graph actions the caller is allowed to perform on the item. Mirrors the annotation of the same name on the `/permissions` endpoint so clients (e.g. a sharing dialog in a search/listing UI) can get the effective-actions view inline without a separate round-trip per item. - Adds `@libre.graph.permissions.actions.allowedValues` to the `driveItem` schema, marked read-only and documented as only populated when requested. - Adds a reusable `driveItemSelect` component parameter with a narrow enum, following the same pattern as PR #38 (feat/download-url). When both land, the enum values merge. - Wires the new parameter to `GetDriveItem`. Rationale discussed in #34.
|
@butonic @aduffeck do we want to hold this back until the additional properties are spec'ed and merged or should we progress here independently? They are not hard to add later and merging this would unblock further work on the search service. edit: Then again, they are "half approved". If we can settle on the |
Adds an optional, `$select`-gated instance annotation on `driveItem` that carries the list of libre.graph actions the caller is allowed to perform on the item. Mirrors the annotation of the same name on the `/permissions` endpoint so clients (e.g. a sharing dialog in a search/listing UI) can get the effective-actions view inline without a separate round-trip per item. - Adds `@libre.graph.permissions.actions.allowedValues` to the `driveItem` schema, marked read-only and documented as only populated when requested. - Adds a reusable `driveItemSelect` component parameter with a narrow enum, following the same pattern as PR #38 (feat/download-url). When both land, the enum values merge. - Wires the new parameter to `GetDriveItem`. Rationale discussed in #34.
|
Implementations for the issues raised above:
I think with those in place we can fully replace the WebDAV search... |
|
I've found more missing properties that WebDAV PROPFIND provides but driveItems don't cover yet. Spec PRs:
Together with the already merged following/tags/allowedValues annotations these cover everything web currently reads - even from PROPFINDs - (share indicators, lock state, processing state) afaict |
d0dceba to
12d8885
Compare
12d8885 to
8f05719
Compare
Generated from opencloud-eu/libre-graph-api#34 rebased onto main: POST /search/query with hits, aggregations and metrics.
ac4bd1d to
fb2b5d7
Compare
|
|
||
| For terms buckets the token is the key encoded as lowercase hex of | ||
| its UTF-8 bytes, prefixed with `ǂǂ` (U+01C2 twice) and wrapped in | ||
| double quotes, e.g. `"ǂǂ5361786f6e"` for the key |
There was a problem hiding this comment.
ms graph does the same weird thing to indicate hex
POST /v1beta1/search/query with searchRequest/searchQuery and the searchResponse/searchHitsContainer/searchHit result types, modeled on the MS Graph search API. The query string is KQL.
aggregationOption with bucketDefinition and manual ranges on the request, searchAggregation/searchBucket on the response, following the MS Graph resource types.
searchBucket carries a server-issued aggregationFilterToken, consumed verbatim through searchRequest.aggregationFilters to narrow a follow-up search to that bucket, matching exactly and case-sensitively. Same encoding MS Graph uses.
@libre.graph.metricDefinition (sum/min/max/avg) on aggregationOption and the @libre.graph.metric result on searchAggregation, the scalar counterpart of bucketDefinition/buckets. Libregraph extension.
@libre.graph.subAggregations nest aggregations within each bucket, on aggregationOption and searchBucket. Libregraph extension.
Libregraph extension: MS Graph search has no $expand and returns no thumbnails on search hits.
Added a new search endpoint for querying resources with detailed request and response structures, including examples for various search scenarios.
Based on the MS Graph Search Api of course:
https://learn.microsoft.com/en-us/graph/api/resources/search-api-overview?view=graph-rest-1.0
I'm also willing to implement that endpoint: opencloud-eu/opencloud#3211
Libregraph extensions beyond MS Graph
Everything follows the MS Graph resource types under the same names, except these additions, which carry the
@libre.graph.prefix like the other libregraph annotations:@libre.graph.subAggregationsonaggregationOptionandsearchBucket: nested aggregations, evaluated in a single request@libre.graph.metricDefinition({ kind }, kind beingsum/min/max/avg) onaggregationOption, mirroringbucketDefinition, with a@libre.graph.metric({ kind, value }) onsearchAggregationinstead ofbucketsExample request with a sub-aggregation and a metric:
{ "requests": [{ "entityTypes": ["driveItem"], "query": { "queryString": "mediatype:audio" }, "size": 0, "aggregations": [{ "field": "audio.artist", "size": 10, "bucketDefinition": { "sortBy": "count", "isDescending": true }, "@libre.graph.subAggregations": [ { "field": "audio.album", "size": 5, "bucketDefinition": { "sortBy": "count" } }, { "field": "audio.duration", "@libre.graph.metricDefinition": { "kind": "sum" } } ] }] }] }And the matching response:
{ "value": [{ "searchTerms": ["mediatype:audio"], "hitsContainers": [{ "hits": [], "total": 142, "moreResultsAvailable": false, "aggregations": [{ "field": "audio.artist", "buckets": [{ "key": "Saxon", "count": 42, "aggregationFilterToken": "\"ǂǂ5361786f6e\"", "@libre.graph.subAggregations": [ { "field": "audio.album", "buckets": [ { "key": "Power & the Glory", "count": 26, "aggregationFilterToken": "\"ǂǂ506f77657220262074686520476c6f7279\"" }, { "key": "Wheels of Steel", "count": 5, "aggregationFilterToken": "\"ǂǂ576865656c73206f6620537465656c\"" } ] }, { "field": "audio.duration", "@libre.graph.metric": { "kind": "sum", "value": 16073000 } } ] }] }] }] }] }aggregationFilterToken
searchBucket.aggregationFilterTokenuses the MS Graph encoding: terms buckets carry the key as a quoted,ǂǂ-prefixed hex token, range buckets arange(from, to)expression withmin/maxfor open bounds andto="le"on an open upper bound, spelled exactly like MS Graph does (whitespace is optional when parsing).aggregationFiltersonly accept server-issued tokens in the{field}:{aggregationFilterToken}form, optionally combined withor(...). The filter matches the bucket key exactly and case-sensitively, so the narrowed result set is the set of matches counted in the bucket.