mirror of
https://github.com/karust/openserp.git
synced 2026-08-06 17:23:55 +08:00
1122 lines
34 KiB
YAML
1122 lines
34 KiB
YAML
openapi: 3.0.3
|
||
info:
|
||
title: OpenSERP API
|
||
version: 1.0.0
|
||
description: >
|
||
OpenSERP provides dedicated and multi-engine search endpoints for Google, Yandex,
|
||
Baidu, Bing, and DuckDuckGo. All responses are wrapped in a v1 envelope with
|
||
query echo, metadata, normalized results, and pagination. Invalid client input
|
||
returns 400 with a machine-readable `reason` code.
|
||
license:
|
||
name: MIT
|
||
url: https://opensource.org/licenses/MIT
|
||
servers:
|
||
- url: http://127.0.0.1:7000
|
||
description: Local default server
|
||
security: []
|
||
tags:
|
||
- name: Search
|
||
description: Dedicated per-engine search endpoints
|
||
- name: Mega
|
||
description: Cross-engine aggregated search endpoints
|
||
- name: Health
|
||
description: Health and readiness endpoints
|
||
- name: Stats
|
||
description: Runtime statistics endpoints
|
||
- name: Docs
|
||
description: OpenAPI and Swagger UI endpoints
|
||
paths:
|
||
/{engine}/search:
|
||
get:
|
||
tags: [Search]
|
||
operationId: searchWeb
|
||
summary: Search web results from a specific engine
|
||
description: >
|
||
Engine path values are `google`, `yandex`, `baidu`, `bing`, and `duck`
|
||
(`duck` maps to DuckDuckGo internally). Use `?format=markdown|text|ndjson`
|
||
for alternative output formats.
|
||
parameters:
|
||
- $ref: "#/components/parameters/EnginePath"
|
||
- $ref: "#/components/parameters/TextQuery"
|
||
- $ref: "#/components/parameters/LangQuery"
|
||
- $ref: "#/components/parameters/DateQuery"
|
||
- $ref: "#/components/parameters/FileQuery"
|
||
- $ref: "#/components/parameters/SiteQuery"
|
||
- $ref: "#/components/parameters/LimitQuery"
|
||
- $ref: "#/components/parameters/StartQuery"
|
||
- $ref: "#/components/parameters/FilterQuery"
|
||
- $ref: "#/components/parameters/AnswersQuery"
|
||
- $ref: "#/components/parameters/FormatQuery"
|
||
- $ref: "#/components/parameters/UseProxyHeader"
|
||
responses:
|
||
"200":
|
||
description: Search results envelope
|
||
headers:
|
||
X-Request-ID:
|
||
$ref: "#/components/headers/XRequestID"
|
||
X-Cache:
|
||
$ref: "#/components/headers/XCache"
|
||
X-Fallback-Engine:
|
||
$ref: "#/components/headers/XFallbackEngine"
|
||
X-Proxy-Mode:
|
||
$ref: "#/components/headers/XProxyMode"
|
||
X-Proxy-Tag:
|
||
$ref: "#/components/headers/XProxyTag"
|
||
X-Proxy-Used:
|
||
$ref: "#/components/headers/XProxyUsed"
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/SearchEnvelope"
|
||
examples:
|
||
default:
|
||
value:
|
||
query:
|
||
text: golang
|
||
lang: EN
|
||
engines_requested: [google]
|
||
meta:
|
||
request_id: 01HXYZ...
|
||
requested_at: "2026-04-24T12:00:00Z"
|
||
took_ms: 842
|
||
engines_failed: []
|
||
version: "1.0"
|
||
results:
|
||
- id: s_a1b2c3d4e5f6a1b2
|
||
rank: 1
|
||
type: organic
|
||
title: The Go Programming Language
|
||
url: https://go.dev/
|
||
display_url: go.dev
|
||
snippet: Go is an open source programming language...
|
||
domain: go.dev
|
||
favicon: https://go.dev/favicon.ico
|
||
is_ad: false
|
||
position:
|
||
absolute: 1
|
||
page: 1
|
||
on_page: 1
|
||
engine: google
|
||
domain_info:
|
||
tld: dev
|
||
sld: go
|
||
is_gov: false
|
||
is_edu: false
|
||
is_mil: false
|
||
is_news: false
|
||
is_forum: false
|
||
is_marketplace: false
|
||
is_social: false
|
||
classification:
|
||
content_type: webpage
|
||
source_hint: ""
|
||
pagination:
|
||
page: 1
|
||
has_more: true
|
||
next_start: 25
|
||
text/markdown:
|
||
schema:
|
||
type: string
|
||
text/plain:
|
||
schema:
|
||
type: string
|
||
application/x-ndjson:
|
||
schema:
|
||
type: string
|
||
"400":
|
||
$ref: "#/components/responses/BadRequestError"
|
||
"503":
|
||
$ref: "#/components/responses/ServiceUnavailableError"
|
||
"404":
|
||
$ref: "#/components/responses/NotFoundError"
|
||
"500":
|
||
$ref: "#/components/responses/InternalServerError"
|
||
/{engine}/image:
|
||
get:
|
||
tags: [Search]
|
||
operationId: searchImages
|
||
summary: Search image results from a specific engine
|
||
parameters:
|
||
- $ref: "#/components/parameters/EnginePath"
|
||
- $ref: "#/components/parameters/TextQuery"
|
||
- $ref: "#/components/parameters/LangQuery"
|
||
- $ref: "#/components/parameters/DateQuery"
|
||
- $ref: "#/components/parameters/FileQuery"
|
||
- $ref: "#/components/parameters/SiteQuery"
|
||
- $ref: "#/components/parameters/LimitQuery"
|
||
- $ref: "#/components/parameters/StartQuery"
|
||
- $ref: "#/components/parameters/FilterQuery"
|
||
- $ref: "#/components/parameters/AnswersQuery"
|
||
- $ref: "#/components/parameters/FormatQuery"
|
||
- $ref: "#/components/parameters/UseProxyHeader"
|
||
responses:
|
||
"200":
|
||
description: Image search results envelope
|
||
headers:
|
||
X-Request-ID:
|
||
$ref: "#/components/headers/XRequestID"
|
||
X-Cache:
|
||
$ref: "#/components/headers/XCache"
|
||
X-Fallback-Engine:
|
||
$ref: "#/components/headers/XFallbackEngine"
|
||
X-Proxy-Mode:
|
||
$ref: "#/components/headers/XProxyMode"
|
||
X-Proxy-Tag:
|
||
$ref: "#/components/headers/XProxyTag"
|
||
X-Proxy-Used:
|
||
$ref: "#/components/headers/XProxyUsed"
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ImageEnvelope"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequestError"
|
||
"503":
|
||
$ref: "#/components/responses/ServiceUnavailableError"
|
||
"404":
|
||
$ref: "#/components/responses/NotFoundError"
|
||
"500":
|
||
$ref: "#/components/responses/InternalServerError"
|
||
/mega/search:
|
||
get:
|
||
tags: [Mega]
|
||
operationId: megaSearch
|
||
summary: Search across multiple engines in parallel
|
||
description: >
|
||
Results are deduplicated by normalized URL. The `clusters` field groups
|
||
results that appeared in multiple engines, scored by cross-engine agreement.
|
||
Partial failures are surfaced in `meta.engines_failed` rather than causing
|
||
a 503. Use `?format=markdown|text|ndjson` for alternative output formats.
|
||
parameters:
|
||
- $ref: "#/components/parameters/TextQuery"
|
||
- $ref: "#/components/parameters/LangQuery"
|
||
- $ref: "#/components/parameters/DateQuery"
|
||
- $ref: "#/components/parameters/FileQuery"
|
||
- $ref: "#/components/parameters/SiteQuery"
|
||
- $ref: "#/components/parameters/LimitQuery"
|
||
- $ref: "#/components/parameters/StartQuery"
|
||
- $ref: "#/components/parameters/FilterQuery"
|
||
- $ref: "#/components/parameters/AnswersQuery"
|
||
- $ref: "#/components/parameters/EnginesQuery"
|
||
- $ref: "#/components/parameters/FormatQuery"
|
||
- $ref: "#/components/parameters/UseProxyHeader"
|
||
responses:
|
||
"200":
|
||
description: Aggregated envelope with clusters
|
||
headers:
|
||
X-Request-ID:
|
||
$ref: "#/components/headers/XRequestID"
|
||
X-Cache:
|
||
$ref: "#/components/headers/XCache"
|
||
X-Proxy-Mode:
|
||
$ref: "#/components/headers/XProxyMode"
|
||
X-Proxy-Tag:
|
||
$ref: "#/components/headers/XProxyTag"
|
||
X-Proxy-Used:
|
||
$ref: "#/components/headers/XProxyUsed"
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/MegaSearchEnvelope"
|
||
text/markdown:
|
||
schema:
|
||
type: string
|
||
text/plain:
|
||
schema:
|
||
type: string
|
||
application/x-ndjson:
|
||
schema:
|
||
type: string
|
||
"400":
|
||
$ref: "#/components/responses/BadRequestError"
|
||
"500":
|
||
$ref: "#/components/responses/InternalServerError"
|
||
/mega/image:
|
||
get:
|
||
tags: [Mega]
|
||
operationId: megaImageSearch
|
||
summary: Image search across multiple engines in parallel
|
||
parameters:
|
||
- $ref: "#/components/parameters/TextQuery"
|
||
- $ref: "#/components/parameters/LangQuery"
|
||
- $ref: "#/components/parameters/DateQuery"
|
||
- $ref: "#/components/parameters/FileQuery"
|
||
- $ref: "#/components/parameters/SiteQuery"
|
||
- $ref: "#/components/parameters/LimitQuery"
|
||
- $ref: "#/components/parameters/StartQuery"
|
||
- $ref: "#/components/parameters/FilterQuery"
|
||
- $ref: "#/components/parameters/AnswersQuery"
|
||
- $ref: "#/components/parameters/EnginesQuery"
|
||
- $ref: "#/components/parameters/FormatQuery"
|
||
- $ref: "#/components/parameters/UseProxyHeader"
|
||
responses:
|
||
"200":
|
||
description: Aggregated image results envelope
|
||
headers:
|
||
X-Request-ID:
|
||
$ref: "#/components/headers/XRequestID"
|
||
X-Cache:
|
||
$ref: "#/components/headers/XCache"
|
||
X-Proxy-Mode:
|
||
$ref: "#/components/headers/XProxyMode"
|
||
X-Proxy-Tag:
|
||
$ref: "#/components/headers/XProxyTag"
|
||
X-Proxy-Used:
|
||
$ref: "#/components/headers/XProxyUsed"
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ImageEnvelope"
|
||
"400":
|
||
$ref: "#/components/responses/BadRequestError"
|
||
"500":
|
||
$ref: "#/components/responses/InternalServerError"
|
||
/mega/engines:
|
||
get:
|
||
tags: [Mega]
|
||
operationId: listMegaEngines
|
||
summary: List available engines and runtime state
|
||
responses:
|
||
"200":
|
||
description: Engine list
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/MegaEnginesResponse"
|
||
/health:
|
||
get:
|
||
tags: [Health]
|
||
operationId: healthCheck
|
||
summary: Service health status
|
||
responses:
|
||
"200":
|
||
description: Healthy or degraded service
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/HealthStatus"
|
||
"503":
|
||
description: Unhealthy service
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/HealthStatus"
|
||
/ready:
|
||
get:
|
||
tags: [Health]
|
||
operationId: readinessCheck
|
||
summary: Service readiness status
|
||
responses:
|
||
"200":
|
||
description: Instance is ready
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ReadinessStatus"
|
||
"503":
|
||
description: Instance is draining
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ReadinessStatus"
|
||
/stats:
|
||
get:
|
||
tags: [Stats]
|
||
operationId: getStats
|
||
summary: Combined cache, proxy, and circuit-breaker stats
|
||
responses:
|
||
"200":
|
||
description: Runtime statistics
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/StatsResponse"
|
||
/stats/cache:
|
||
get:
|
||
tags: [Stats]
|
||
operationId: getCacheStats
|
||
summary: Cache statistics only
|
||
responses:
|
||
"200":
|
||
description: Cache status
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/CacheStats"
|
||
/stats/proxy:
|
||
get:
|
||
tags: [Stats]
|
||
operationId: getProxyStats
|
||
summary: Proxy pool and per-engine proxy policy statistics
|
||
responses:
|
||
"200":
|
||
description: Proxy stats
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ProxyStats"
|
||
/stats/cb:
|
||
get:
|
||
tags: [Stats]
|
||
operationId: getCircuitBreakerStats
|
||
summary: Circuit breaker state per engine
|
||
responses:
|
||
"200":
|
||
description: Circuit breaker stats
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/CircuitBreakerStatsResponse"
|
||
/openapi.yaml:
|
||
get:
|
||
tags: [Docs]
|
||
operationId: getOpenAPISpec
|
||
summary: Get raw OpenAPI YAML
|
||
responses:
|
||
"200":
|
||
description: OpenAPI YAML
|
||
content:
|
||
application/yaml:
|
||
schema:
|
||
type: string
|
||
/docs:
|
||
get:
|
||
tags: [Docs]
|
||
operationId: getSwaggerUI
|
||
summary: Swagger UI for interactive API docs
|
||
responses:
|
||
"200":
|
||
description: HTML page loading Swagger UI from CDN
|
||
content:
|
||
text/html:
|
||
schema:
|
||
type: string
|
||
components:
|
||
parameters:
|
||
EnginePath:
|
||
name: engine
|
||
in: path
|
||
required: true
|
||
description: Search engine endpoint alias (`duck` is DuckDuckGo).
|
||
schema:
|
||
type: string
|
||
enum: [google, yandex, baidu, bing, duck]
|
||
TextQuery:
|
||
name: text
|
||
in: query
|
||
required: false
|
||
description: >
|
||
Search query text. At least one of `text`, `site`, or `file` must be non-empty.
|
||
schema:
|
||
type: string
|
||
example: golang
|
||
LangQuery:
|
||
name: lang
|
||
in: query
|
||
required: false
|
||
description: Language code (engine-specific behavior).
|
||
schema:
|
||
type: string
|
||
example: EN
|
||
DateQuery:
|
||
name: date
|
||
in: query
|
||
required: false
|
||
description: Date interval in `YYYYMMDD..YYYYMMDD` format.
|
||
schema:
|
||
type: string
|
||
pattern: "^[0-9]{8}\\.\\.[0-9]{8}$"
|
||
example: 20250101..20250131
|
||
FileQuery:
|
||
name: file
|
||
in: query
|
||
required: false
|
||
description: File extension filter (for engines that support it).
|
||
schema:
|
||
type: string
|
||
example: PDF
|
||
SiteQuery:
|
||
name: site
|
||
in: query
|
||
required: false
|
||
description: Site/domain filter.
|
||
schema:
|
||
type: string
|
||
example: github.com
|
||
LimitQuery:
|
||
name: limit
|
||
in: query
|
||
required: false
|
||
description: Maximum results to return (1–100).
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 100
|
||
default: 25
|
||
example: 10
|
||
StartQuery:
|
||
name: start
|
||
in: query
|
||
required: false
|
||
description: Pagination offset (must be >= 0).
|
||
schema:
|
||
type: integer
|
||
minimum: 0
|
||
default: 0
|
||
example: 20
|
||
FilterQuery:
|
||
name: filter
|
||
in: query
|
||
required: false
|
||
description: Duplicate filtering flag (primarily used by Google parser behavior).
|
||
schema:
|
||
type: boolean
|
||
default: true
|
||
AnswersQuery:
|
||
name: answers
|
||
in: query
|
||
required: false
|
||
description: Include answer box style results when supported.
|
||
schema:
|
||
type: boolean
|
||
default: false
|
||
EnginesQuery:
|
||
name: engines
|
||
in: query
|
||
required: false
|
||
description: >
|
||
Comma-separated engine list for mega endpoints. If omitted, all available engines are used.
|
||
schema:
|
||
type: string
|
||
example: google,bing,duckduckgo
|
||
FormatQuery:
|
||
name: format
|
||
in: query
|
||
required: false
|
||
description: >
|
||
Output format. `json` (default) returns the full envelope. `markdown` returns a
|
||
Markdown document suitable for Slack/email. `text` returns a minimal plain-text
|
||
block optimised for LLM context windows. `ndjson` returns one result object per
|
||
line with no envelope. The `Accept` header is also checked
|
||
(`text/markdown`, `text/plain`, `application/x-ndjson`).
|
||
schema:
|
||
type: string
|
||
enum: [json, markdown, text, ndjson]
|
||
default: json
|
||
UseProxyHeader:
|
||
name: X-Use-Proxy
|
||
in: header
|
||
required: false
|
||
description: >
|
||
Request-scoped proxy override. Use `direct` to disable proxy or a tag name to
|
||
force a specific proxy pool.
|
||
schema:
|
||
type: string
|
||
examples:
|
||
direct:
|
||
value: direct
|
||
tag:
|
||
value: us
|
||
headers:
|
||
XRequestID:
|
||
description: >
|
||
UUID v7 request identifier. Matches `meta.request_id` in the response body and
|
||
appears in server logs for correlation.
|
||
schema:
|
||
type: string
|
||
XCache:
|
||
description: Cache status when cache is enabled (`HIT`, `MISS`, `BYPASS`).
|
||
schema:
|
||
type: string
|
||
enum: [HIT, MISS, BYPASS]
|
||
XFallbackEngine:
|
||
description: Engine name used when dedicated endpoint fallback served the response.
|
||
schema:
|
||
type: string
|
||
XProxyMode:
|
||
description: Effective proxy mode for the request (`off` or `tag_pool`).
|
||
schema:
|
||
type: string
|
||
enum: [off, tag_pool]
|
||
XProxyTag:
|
||
description: Effective proxy tag when `X-Proxy-Mode=tag_pool`.
|
||
schema:
|
||
type: string
|
||
XProxyUsed:
|
||
description: Effective proxy target used (`direct`, masked URL, `pooled`, `multiple`, `mixed`).
|
||
schema:
|
||
type: string
|
||
responses:
|
||
BadRequestError:
|
||
description: Invalid request parameters
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ErrorResponse"
|
||
examples:
|
||
invalidLimit:
|
||
value:
|
||
error: bad_request
|
||
code: 400
|
||
message: "INVALID_LIMIT: limit must be between 1 and 100"
|
||
reason: INVALID_LIMIT
|
||
emptyQuery:
|
||
value:
|
||
error: bad_request
|
||
code: 400
|
||
message: "EMPTY_QUERY: query cannot be empty"
|
||
reason: EMPTY_QUERY
|
||
ServiceUnavailableError:
|
||
description: Search failed and no result could be produced
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ErrorResponse"
|
||
examples:
|
||
primaryFailed:
|
||
value:
|
||
error: service_unavailable
|
||
code: 503
|
||
message: all search engines failed
|
||
NotFoundError:
|
||
description: Endpoint not found
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ErrorResponse"
|
||
InternalServerError:
|
||
description: Internal error while handling request
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/ErrorResponse"
|
||
schemas:
|
||
# ── v1 envelope ──────────────────────────────────────────────────
|
||
QueryEcho:
|
||
type: object
|
||
required: [text, engines_requested]
|
||
properties:
|
||
text:
|
||
type: string
|
||
example: golang
|
||
lang:
|
||
type: string
|
||
example: EN
|
||
engines_requested:
|
||
type: array
|
||
items:
|
||
type: string
|
||
example: [google]
|
||
ResponseMeta:
|
||
type: object
|
||
required: [request_id, requested_at, took_ms, engines_failed, version]
|
||
properties:
|
||
request_id:
|
||
type: string
|
||
example: 01HXYZ...
|
||
requested_at:
|
||
type: string
|
||
format: date-time
|
||
example: "2026-04-24T12:00:00Z"
|
||
took_ms:
|
||
type: integer
|
||
example: 842
|
||
engines_failed:
|
||
type: array
|
||
items:
|
||
type: string
|
||
example: []
|
||
version:
|
||
type: string
|
||
example: "1.0"
|
||
Pagination:
|
||
type: object
|
||
required: [page, has_more, next_start]
|
||
properties:
|
||
page:
|
||
type: integer
|
||
minimum: 1
|
||
example: 1
|
||
has_more:
|
||
type: boolean
|
||
example: true
|
||
next_start:
|
||
type: integer
|
||
example: 25
|
||
# ── Result ───────────────────────────────────────────────────────
|
||
Position:
|
||
type: object
|
||
required: [absolute, page, on_page]
|
||
properties:
|
||
absolute:
|
||
type: integer
|
||
description: 1-based rank counting from the first result of the first page.
|
||
example: 1
|
||
page:
|
||
type: integer
|
||
example: 1
|
||
on_page:
|
||
type: integer
|
||
example: 1
|
||
DomainInfo:
|
||
type: object
|
||
required: [tld, sld, is_gov, is_edu, is_mil, is_news, is_forum, is_marketplace, is_social]
|
||
properties:
|
||
tld:
|
||
type: string
|
||
example: org
|
||
sld:
|
||
type: string
|
||
example: wikipedia
|
||
is_gov:
|
||
type: boolean
|
||
is_edu:
|
||
type: boolean
|
||
is_mil:
|
||
type: boolean
|
||
is_news:
|
||
type: boolean
|
||
is_forum:
|
||
type: boolean
|
||
is_marketplace:
|
||
type: boolean
|
||
is_social:
|
||
type: boolean
|
||
Classification:
|
||
type: object
|
||
required: [content_type, source_hint]
|
||
properties:
|
||
content_type:
|
||
type: string
|
||
enum: [article, document, video, forum_thread, webpage]
|
||
example: article
|
||
source_hint:
|
||
type: string
|
||
example: encyclopedia
|
||
ResultType:
|
||
type: string
|
||
description: >
|
||
SERP block type. New values require a minor version bump (`meta.version: "1.1"`).
|
||
In v1.0, engines emit `organic`, `ad`, or `answer_box`; other enum values are
|
||
reserved for future parser upgrades.
|
||
enum:
|
||
- organic
|
||
- ad
|
||
- featured_snippet
|
||
- knowledge_panel
|
||
- people_also_ask
|
||
- video
|
||
- image
|
||
- news
|
||
- shopping
|
||
- local
|
||
- answer_box
|
||
Result:
|
||
type: object
|
||
required:
|
||
- id
|
||
- rank
|
||
- type
|
||
- title
|
||
- url
|
||
- display_url
|
||
- snippet
|
||
- domain
|
||
- favicon
|
||
- is_ad
|
||
- position
|
||
- engine
|
||
properties:
|
||
id:
|
||
type: string
|
||
description: >
|
||
Stable identifier: `s_` + hex(first 8 bytes of MD5(engine|normalized_url)).
|
||
Normalized URL: lowercase scheme+host, trailing slash stripped, utm_*/fbclid/gclid
|
||
tracking params removed. Same URL → same ID across requests.
|
||
example: s_a1b2c3d4e5f6a1b2
|
||
rank:
|
||
type: integer
|
||
example: 1
|
||
type:
|
||
$ref: "#/components/schemas/ResultType"
|
||
title:
|
||
type: string
|
||
example: The Go Programming Language
|
||
url:
|
||
type: string
|
||
example: https://go.dev/
|
||
display_url:
|
||
type: string
|
||
description: Breadcrumb form of the URL (e.g. `go.dev › doc › install`).
|
||
example: go.dev
|
||
snippet:
|
||
type: string
|
||
example: Go is an open source programming language...
|
||
domain:
|
||
type: string
|
||
description: Registrable domain with leading `www.` stripped.
|
||
example: go.dev
|
||
favicon:
|
||
type: string
|
||
description: Constructed as `https://{domain}/favicon.ico`. Not probed.
|
||
example: https://go.dev/favicon.ico
|
||
is_ad:
|
||
type: boolean
|
||
example: false
|
||
position:
|
||
$ref: "#/components/schemas/Position"
|
||
engine:
|
||
type: string
|
||
example: google
|
||
domain_info:
|
||
$ref: "#/components/schemas/DomainInfo"
|
||
classification:
|
||
$ref: "#/components/schemas/Classification"
|
||
# ── Image result ─────────────────────────────────────────────────
|
||
ImageData:
|
||
type: object
|
||
required: [url]
|
||
properties:
|
||
url:
|
||
type: string
|
||
example: https://example.com/gopher.png
|
||
thumbnail:
|
||
type: string
|
||
example: https://example.com/gopher-thumb.png
|
||
width:
|
||
type: integer
|
||
example: 1200
|
||
height:
|
||
type: integer
|
||
example: 800
|
||
ImageSource:
|
||
type: object
|
||
required: [page_url, domain]
|
||
properties:
|
||
page_url:
|
||
type: string
|
||
example: https://example.com/article-about-gophers
|
||
domain:
|
||
type: string
|
||
example: example.com
|
||
ImageResult:
|
||
type: object
|
||
required: [id, rank, type, title, image, source, engine]
|
||
properties:
|
||
id:
|
||
type: string
|
||
description: Stable identifier prefixed with `i_`.
|
||
example: i_a1b2c3d4e5f6a1b2
|
||
rank:
|
||
type: integer
|
||
example: 1
|
||
type:
|
||
type: string
|
||
enum: [image]
|
||
title:
|
||
type: string
|
||
image:
|
||
$ref: "#/components/schemas/ImageData"
|
||
source:
|
||
$ref: "#/components/schemas/ImageSource"
|
||
engine:
|
||
type: string
|
||
# ── Clusters (mega only) ──────────────────────────────────────────
|
||
ClusterOccurrence:
|
||
type: object
|
||
required: [engine, rank, result_id]
|
||
properties:
|
||
engine:
|
||
type: string
|
||
example: google
|
||
rank:
|
||
type: integer
|
||
example: 1
|
||
result_id:
|
||
type: string
|
||
example: s_a1b2c3d4e5f6a1b2
|
||
Cluster:
|
||
type: object
|
||
required: [id, canonical_url, domain, title, occurrences, engines_count, best_rank, score]
|
||
properties:
|
||
id:
|
||
type: string
|
||
description: >
|
||
Stable identifier: `c_` + hex(first 8 bytes of MD5(normalized_url)).
|
||
example: c_a1b2c3d4e5f6a1b2
|
||
canonical_url:
|
||
type: string
|
||
example: https://go.dev/
|
||
domain:
|
||
type: string
|
||
example: go.dev
|
||
title:
|
||
type: string
|
||
example: The Go Programming Language
|
||
occurrences:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/ClusterOccurrence"
|
||
engines_count:
|
||
type: integer
|
||
description: Number of engines this URL appeared in.
|
||
example: 3
|
||
best_rank:
|
||
type: integer
|
||
description: Lowest (best) rank seen across all engines.
|
||
example: 1
|
||
score:
|
||
type: number
|
||
format: float
|
||
description: >
|
||
Cross-engine agreement score: sum(1/rank for each occurrence) / engines_queried,
|
||
capped at 1.0. Higher is better.
|
||
example: 0.92
|
||
# ── Envelopes ─────────────────────────────────────────────────────
|
||
SearchEnvelope:
|
||
type: object
|
||
required: [query, meta, results, pagination]
|
||
properties:
|
||
query:
|
||
$ref: "#/components/schemas/QueryEcho"
|
||
meta:
|
||
$ref: "#/components/schemas/ResponseMeta"
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/Result"
|
||
pagination:
|
||
$ref: "#/components/schemas/Pagination"
|
||
MegaSearchEnvelope:
|
||
allOf:
|
||
- $ref: "#/components/schemas/SearchEnvelope"
|
||
- type: object
|
||
properties:
|
||
clusters:
|
||
type: array
|
||
nullable: true
|
||
items:
|
||
$ref: "#/components/schemas/Cluster"
|
||
description: >
|
||
Cross-engine clusters, sorted by score descending. Only present on
|
||
/mega/search responses. Absent (not null) on single-engine endpoints.
|
||
ImageEnvelope:
|
||
type: object
|
||
required: [query, meta, results, pagination]
|
||
properties:
|
||
query:
|
||
$ref: "#/components/schemas/QueryEcho"
|
||
meta:
|
||
$ref: "#/components/schemas/ResponseMeta"
|
||
results:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/ImageResult"
|
||
pagination:
|
||
$ref: "#/components/schemas/Pagination"
|
||
# ── Error ─────────────────────────────────────────────────────────
|
||
ErrorResponse:
|
||
type: object
|
||
required: [error, code]
|
||
properties:
|
||
error:
|
||
type: string
|
||
description: Stable machine-readable error class.
|
||
enum: [bad_request, not_found, rate_limited, service_unavailable, server_error, client_error, error]
|
||
example: bad_request
|
||
code:
|
||
type: integer
|
||
example: 400
|
||
message:
|
||
type: string
|
||
example: "INVALID_LIMIT: limit must be between 1 and 100"
|
||
reason:
|
||
type: string
|
||
description: >
|
||
Stable client-actionable reason code. Present on 400 errors.
|
||
Known values: INVALID_LIMIT, INVALID_START, INVALID_PARAM, EMPTY_QUERY,
|
||
NO_ENGINES, UNKNOWN_FORMAT.
|
||
example: INVALID_LIMIT
|
||
# ── Health / Stats ────────────────────────────────────────────────
|
||
EngineHealth:
|
||
type: object
|
||
required: [name, initialized, status]
|
||
properties:
|
||
name:
|
||
type: string
|
||
example: google
|
||
initialized:
|
||
type: boolean
|
||
example: true
|
||
status:
|
||
type: string
|
||
enum: [ready, not_initialized, circuit_open]
|
||
HealthStatus:
|
||
type: object
|
||
required: [status, uptime, engines, system]
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [healthy, degraded, unhealthy]
|
||
uptime:
|
||
type: string
|
||
example: 1h12m3s
|
||
engines:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/EngineHealth"
|
||
system:
|
||
type: object
|
||
additionalProperties: true
|
||
ReadinessStatus:
|
||
type: object
|
||
required: [status]
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [ready, draining]
|
||
CacheStatsEnabled:
|
||
type: object
|
||
required: [status, entries, hits, misses, bypasses, evictions, ttl_seconds, max_size]
|
||
properties:
|
||
status:
|
||
type: boolean
|
||
enum: [true]
|
||
entries:
|
||
type: integer
|
||
hits:
|
||
type: integer
|
||
misses:
|
||
type: integer
|
||
bypasses:
|
||
type: integer
|
||
evictions:
|
||
type: integer
|
||
ttl_seconds:
|
||
type: integer
|
||
max_size:
|
||
type: integer
|
||
CacheStatsDisabled:
|
||
type: object
|
||
required: [status]
|
||
properties:
|
||
status:
|
||
type: boolean
|
||
enum: [false]
|
||
CacheStats:
|
||
oneOf:
|
||
- $ref: "#/components/schemas/CacheStatsEnabled"
|
||
- $ref: "#/components/schemas/CacheStatsDisabled"
|
||
ProxyTagSummary:
|
||
type: object
|
||
required: [configured, healthy]
|
||
properties:
|
||
configured:
|
||
type: integer
|
||
healthy:
|
||
type: integer
|
||
ProxyStatsEntry:
|
||
type: object
|
||
required: [proxy, tags, healthy, failures, disabled]
|
||
properties:
|
||
proxy:
|
||
type: string
|
||
tags:
|
||
type: array
|
||
items:
|
||
type: string
|
||
healthy:
|
||
type: boolean
|
||
failures:
|
||
type: integer
|
||
disabled:
|
||
type: boolean
|
||
ProxyEngineStats:
|
||
type: object
|
||
required: [selected_proxy]
|
||
properties:
|
||
tag:
|
||
type: string
|
||
selected_proxy:
|
||
type: string
|
||
ProxyStats:
|
||
type: object
|
||
required: [configured_count, healthy_count, unhealthy_count, tags, entries]
|
||
properties:
|
||
configured_count:
|
||
type: integer
|
||
healthy_count:
|
||
type: integer
|
||
unhealthy_count:
|
||
type: integer
|
||
tags:
|
||
type: object
|
||
additionalProperties:
|
||
$ref: "#/components/schemas/ProxyTagSummary"
|
||
entries:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/ProxyStatsEntry"
|
||
engines:
|
||
type: object
|
||
additionalProperties:
|
||
$ref: "#/components/schemas/ProxyEngineStats"
|
||
CircuitBreakerStat:
|
||
type: object
|
||
required: [engine, state, failure_count, last_changed]
|
||
properties:
|
||
engine:
|
||
type: string
|
||
state:
|
||
type: string
|
||
enum: [closed, open, half-open]
|
||
failure_count:
|
||
type: integer
|
||
last_changed:
|
||
type: string
|
||
format: date-time
|
||
retry_in:
|
||
type: integer
|
||
description: Seconds until next half-open attempt (present when state is open).
|
||
CircuitBreakerStatsResponse:
|
||
type: object
|
||
required: [circuit_breakers]
|
||
properties:
|
||
circuit_breakers:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/CircuitBreakerStat"
|
||
StatsResponse:
|
||
type: object
|
||
required: [cache, proxy, circuit_breakers]
|
||
properties:
|
||
cache:
|
||
$ref: "#/components/schemas/CacheStats"
|
||
proxy:
|
||
$ref: "#/components/schemas/ProxyStats"
|
||
circuit_breakers:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/CircuitBreakerStat"
|
||
MegaEngineInfo:
|
||
type: object
|
||
required: [name, initialized]
|
||
properties:
|
||
name:
|
||
type: string
|
||
initialized:
|
||
type: boolean
|
||
circuit_state:
|
||
type: string
|
||
enum: [closed, open, half-open]
|
||
MegaEnginesResponse:
|
||
type: object
|
||
required: [engines, total]
|
||
properties:
|
||
engines:
|
||
type: array
|
||
items:
|
||
$ref: "#/components/schemas/MegaEngineInfo"
|
||
total:
|
||
type: integer
|