Skip to content

Latest commit

 

History

History
215 lines (157 loc) · 5.39 KB

api-contract.md

File metadata and controls

215 lines (157 loc) · 5.39 KB

API Contract

Overview

SearchOps exposes a small REST API for public job discovery, event tracking, analytics, experimentation, health checks, and local observability.

The product API uses JSON envelopes. Infrastructure endpoints may use different response formats when appropriate, such as Prometheus-style text for /metrics.

URL Groups

Area Base URL Purpose
Infrastructure http://localhost:5000 Health, metrics, and developer docs
Product API http://localhost:5000/api Jobs, events, analytics, and experiments

Implemented Endpoints

Endpoint Purpose
GET /health Verify the backend service is running
GET /metrics Return Prometheus-style operational metrics
GET /api/jobs List, search, filter, sort, and paginate jobs
GET /api/jobs/:slug Fetch one job by SEO-friendly slug
POST /api/events Track job views, apply clicks, search, and filter events
GET /api/analytics/summary Return lightweight product analytics
POST /api/experiments/apply-cta-assignment Return and persist anonymous apply CTA assignment

Developer docs:

Route Purpose
GET /api-docs Swagger UI for the checked-in OpenAPI file
GET /api-docs/openapi.yaml Raw OpenAPI YAML served by the backend

/api-docs is not a product API endpoint.

Response Format

Product API success response:

{
  "data": {},
  "meta": {
    "timestamp": "2026-05-11T06:30:00.000Z",
    "requestId": "req_abc123"
  }
}

Product API error response:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid query parameter",
    "details": []
  },
  "meta": {
    "timestamp": "2026-05-11T06:30:00.000Z",
    "requestId": "req_abc123"
  }
}

Current error codes:

Code HTTP Description
VALIDATION_ERROR 400 Invalid query string, path parameter, or request body
NOT_FOUND 404 Requested route, job, or referenced job does not exist
INTERNAL_ERROR 500 Unhandled application error

Infrastructure Endpoints

GET /health

Returns the standard JSON envelope:

{
  "data": {
    "status": "ok"
  },
  "meta": {
    "timestamp": "2026-05-11T06:30:00.000Z",
    "requestId": "req_abc123"
  }
}

GET /metrics

Returns text/plain; version=0.0.4; charset=utf-8 and does not use the JSON envelope.

Implemented metrics:

http_requests_total
http_errors_total
http_request_duration_ms
search_latency_simulation_total

Example:

http_requests_total{method="GET",route="/api/jobs",statusCode="200"} 1
http_request_duration_ms_count{method="GET",route="/api/jobs",statusCode="200"} 1

Job Endpoints

GET /api/jobs

Returns a paginated list of jobs.

Query parameters:

Parameter Type Default Notes
q string none Keyword search across title, description, location, company name, and company slug
keyword string none Alias for q; q wins when both are provided
location string none Case-insensitive partial match
category enum none SOFTWARE_ENGINEERING, DATA_ANALYTICS, CLOUD_DEVOPS, PRODUCT, DESIGN, CYBERSECURITY
workMode enum none ONSITE, HYBRID, REMOTE
employmentType enum none FULL_TIME, PART_TIME, CONTRACT, CASUAL, INTERNSHIP
company string none Case-insensitive partial match on company name or slug
salaryMin integer none Jobs whose salaryMax is greater than or equal to this value
salaryMax integer none Jobs whose salaryMin is less than or equal to this value
page integer 1 Must be positive
limit integer 20 Must be positive, max 100
sort enum recent recent, salary_desc, salary_asc

GET /api/jobs/:slug

Fetches one public job by SEO-friendly slug. Unknown slugs return 404 NOT_FOUND.

Event Endpoint

POST /api/events

Request body:

{
  "eventType": "JOB_VIEW",
  "jobId": "clxjob001",
  "variant": "A",
  "searchTerm": "backend"
}

Rules:

  • eventType is required: JOB_VIEW, APPLY_CLICK, SEARCH_PERFORMED, or FILTER_USED.
  • JOB_VIEW and APPLY_CLICK require jobId.
  • variant, when provided, must be A or B.
  • If jobId is provided, the referenced job must exist.

Success status: 201.

Analytics Endpoint

GET /api/analytics/summary

Returns:

  • total job views
  • total apply clicks
  • overall apply click-through rate
  • top searched keywords
  • most viewed jobs
  • conversion by variant

This is intentionally lightweight and not a production analytics warehouse.

Experiment Endpoint

POST /api/experiments/apply-cta-assignment

Request body:

{
  "anonymousUserId": "anon_demo_user"
}

The backend checks for an existing assignment for apply_cta_copy. If none exists, it uses a stable hash of anonymousUserId, persists variant A or B, and returns the corresponding CTA text.

Variant CTA text
A Apply now
B Start your application

OpenAPI

The current OpenAPI contract is maintained in openapi.yaml.

When the backend is running, Swagger UI is available at:

http://localhost:5000/api-docs

Out of Scope

  • Authentication and authorization
  • Rate limiting
  • Admin APIs
  • Real job application submission
  • Full-text search index and relevance ranking
  • Production analytics pipeline