Skip to content

Add complete Robin-Camp application with movie and rating APIs #1

Add complete Robin-Camp application with movie and rating APIs

Add complete Robin-Camp application with movie and rating APIs #1

Workflow file for this run

openapi: 3.0.3

Check failure on line 1 in .github/workflows/openapi.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/openapi.yml

Invalid workflow file

(Line: 1, Col: 1): Unexpected value 'openapi', (Line: 2, Col: 1): Unexpected value 'info', (Line: 13, Col: 1): Unexpected value 'servers', (Line: 15, Col: 1): Unexpected value 'tags', (Line: 18, Col: 1): Unexpected value 'paths', (Line: 244, Col: 1): Unexpected value 'components', (Line: 1, Col: 1): Required property is missing: jobs
info:
title: Movies API
version: "1.0.0"
description: >
Movie service API with the following constraints:
- After successful movie creation, synchronously call upstream box office API `GET /boxoffice?title=...`:
* If upstream returns **200**: merge `{revenue, distributor, releaseDate, budget, mpaRating, currency, source, lastUpdated}` into movie record.
* If upstream fails (e.g., **404**): set `boxOffice = null`, do not block creation process.
- Rating submission requires authentication (header `X-Rater-Id`), ratings for same `(movieTitle, raterId)` follow **Upsert** semantics.
- Rating aggregation returns `{average, count}`, with average rounded to **1 decimal place**.
- List search supports `q | year | distributor | budget | mpaRating | genre | limit | cursor`, pagination response is fixed as `items[] + nextCursor`.
servers:
- url: https://api.example.com
tags:
- name: Movies
- name: Ratings
paths:
/movies:
get:
tags: [Movies]
summary: List and search movies
parameters:
- in: query
name: q
schema: { type: string }
description: Keyword search (e.g., fuzzy matching of titles).
- in: query
name: year
schema: { type: integer }
description: Exact match for release year (extracted from releaseDate).
- in: query
name: genre
schema: { type: string }
description: Exact match for genre (case-insensitive implementation determined by server).
- in: query
name: distributor
schema: { type: string }
description: Exact match for distributor (case-insensitive implementation determined by server).
- in: query
name: budget
schema: { type: integer, format: int64 }
description: Filter movies with production budget less than or equal to the specified amount in USD.
- in: query
name: mpaRating
schema: { type: string }
description: Exact match for MPA rating (e.g., G, PG, PG-13, R, NC-17).
- in: query
name: limit
schema:
type: integer
minimum: 1
description: Number of items per page.
- in: query
name: cursor
schema: { type: string }
description: The `nextCursor` returned from previous page, used to get next page.
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/MoviePage"
examples:
sample:
value:
items:
- id: "m_123"
title: "Inception"
releaseDate: "2010-07-16"
genre: "Sci-Fi"
distributor: "Warner Bros. Pictures"
budget: 160000000
mpaRating: "PG-13"
boxOffice:
revenue:
worldwide: 829895144
openingWeekendUsa: 62785337
currency: "USD"
source: "ExampleBoxOfficeAPI"
lastUpdated: "2025-09-23T12:00:00Z"
nextCursor: "eyJvZmZzZXQiOjIwMH0="
"400":
$ref: "#/components/responses/BadRequest"
post:
tags: [Movies]
summary: Create movie (synchronously query and merge box office data after success)
description: |
- Create movie record with `title`, `genre`, and `releaseDate` as required fields.
- After successful creation, synchronously call upstream `GET /boxoffice?title=...`:
* Upstream 200: merge `{revenue, distributor, budget, mpaRating, currency, source, lastUpdated}` into movie record, **but user-provided values take precedence**;
* Upstream non-200 (e.g., 404): set `boxOffice = null` and leave `distributor`, `budget`, `mpaRating` as `null` if not provided by user; **do not block creation**.
- **Priority rule**: User-provided fields (distributor, budget, mpaRating) always take precedence over corresponding data from the box office API.
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MovieCreate"
examples:
create_minimal:
value:
title: "Inception"
genre: "Sci-Fi"
releaseDate: "2010-07-16"
create_full:
value:
title: "Inception"
genre: "Sci-Fi"
releaseDate: "2010-07-16"
distributor: "Warner Bros. Pictures"
budget: 160000000
mpaRating: "PG-13"
responses:
"201":
description: Created
headers:
Location:
description: Absolute path of the newly created resource
schema:
type: string
format: uri
content:
application/json:
schema:
$ref: "#/components/schemas/Movie"
examples:
created:
value:
id: "m_123"
title: "Inception"
releaseDate: "2010-07-16"
genre: "Sci-Fi"
distributor: "Warner Bros. Pictures"
budget: 160000000
mpaRating: "PG-13"
boxOffice:
revenue:
worldwide: 829895144
openingWeekendUsa: 62785337
currency: "USD"
source: "ExampleBoxOfficeAPI"
lastUpdated: "2025-09-23T12:00:00Z"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/movies/{title}/ratings:
post:
tags: [Ratings]
summary: Submit rating (Upsert)
description: |
- Requires request header `X-Rater-Id`.
- Upsert semantics: submitting again for same `(movieTitle, raterId)` will overwrite the rating.
- `rating` value set: `{0.5, 1.0, …, 5.0}` (step size 0.5).
security:
- RaterId: []
parameters:
- in: path
name: title
required: true
schema: { type: string }
description: Movie title
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RatingSubmit"
examples:
upsert:
value:
rating: 4.5
responses:
"201":
description: New rating created
headers:
Location:
description: Location of the rating resource after creation or update (optional)
schema: { type: string, format: uri }
content:
application/json:
schema:
$ref: "#/components/schemas/RatingResult"
examples:
created:
value:
movieTitle: "Inception"
raterId: "user_456"
rating: 4.5
"200":
description: Rating overwritten (updated)
content:
application/json:
schema:
$ref: "#/components/schemas/RatingResult"
examples:
updated:
value:
movieTitle: "Inception"
raterId: "user_456"
rating: 3.0
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
/movies/{title}/rating:
get:
tags: [Ratings]
summary: Rating aggregation
description: Returns `{average, count}`, where `average` is rounded to **1 decimal place**.
parameters:
- in: path
name: title
required: true
schema: { type: string }
description: Movie title
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/RatingAggregate"
examples:
agg:
value:
average: 4.3
count: 128
"404":
$ref: "#/components/responses/NotFound"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
RaterId:
type: apiKey
in: header
name: X-Rater-Id
schemas:
MovieCreate:
type: object
additionalProperties: false
required: [title, genre, releaseDate]
properties:
title:
type: string
description: Movie title
minLength: 1
genre:
type: string
description: Genre
releaseDate:
type: string
format: date
description: The original theatrical release date in North America.
example: "2010-07-16"
distributor:
type: string
description: The company that distributed the movie. User-provided value takes precedence over box office API data.
example: "Warner Bros. Pictures"
budget:
type: integer
format: int64
description: The estimated production budget of the movie in USD. User-provided value takes precedence over box office API data.
example: 160000000
mpaRating:
type: string
description: The MPA (Motion Picture Association) rating. User-provided value takes precedence over box office API data.
example: "PG-13"
BoxOffice:
type: object
additionalProperties: false
properties:
revenue:
type: object
properties:
worldwide:
type: integer
format: int64
description: The total worldwide gross revenue in USD.
example: 829895144
openingWeekendUSA:
type: integer
format: int64
description: The opening weekend gross revenue in the USA in USD.
example: 62785337
required: [worldwide]
currency:
type: string
description: Currency code (e.g., USD)
example: "USD"
source:
type: string
description: Data source identifier
example: "ExampleBoxOfficeAPI"
lastUpdated:
type: string
format: date-time
description: Last update time from upstream (UTC)
example: "2025-09-23T12:00:00Z"
required: [revenue, currency, source, lastUpdated]
Movie:
type: object
additionalProperties: false
properties:
id:
type: string
description: Movie ID
title:
type: string
releaseDate:
type: string
format: date
description: The original theatrical release date in North America.
example: "2010-07-16"
genre:
type: string
distributor:
type: string
description: The company that distributed the movie.
example: "Warner Bros. Pictures"
budget:
type: integer
format: int64
description: The estimated production budget of the movie in USD.
example: 160000000
mpaRating:
type: string
description: The MPA (Motion Picture Association) rating.
example: "PG-13"
boxOffice:
allOf:
- $ref: "#/components/schemas/BoxOffice"
nullable: true
required: [id, title, genre, releaseDate]
RatingSubmit:
type: object
additionalProperties: false
required: [rating]
properties:
rating:
type: number
description: Rating value from `{0.5, 1.0, …, 5.0}`
enum:
- 0.5
- 1.0
- 1.5
- 2.0
- 2.5
- 3.0
- 3.5
- 4.0
- 4.5
- 5.0
RatingResult:
type: object
additionalProperties: false
properties:
movieTitle:
type: string
raterId:
type: string
description: Taken from request header `X-Rater-Id`
rating:
type: number
description: Rating value from `{0.5, 1.0, …, 5.0}`
enum:
- 0.5
- 1.0
- 1.5
- 2.0
- 2.5
- 3.0
- 3.5
- 4.0
- 4.5
- 5.0
required: [movieTitle, raterId, rating]
RatingAggregate:
type: object
additionalProperties: false
properties:
average:
type: number
description: Average rating; rounded to 1 decimal place
count:
type: integer
description: Total number of ratings
required: [average, count]
MoviePage:
type: object
additionalProperties: false
properties:
items:
type: array
items:
$ref: "#/components/schemas/Movie"
nextCursor:
type: string
nullable: true
description: Next page cursor; `null` or omitted when no more data
required: [items]
Error:
type: object
additionalProperties: false
properties:
code:
type: string
description: Error code (readable)
message:
type: string
description: Error description
details:
description: Additional information
required: [code, message]
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
examples:
bad:
value: { code: "BAD_REQUEST", message: "Invalid parameters" }
Unauthorized:
description: Unauthorized (missing or invalid `X-Rater-Id`)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
examples:
unauth:
value: { code: "UNAUTHORIZED", message: "Missing or invalid authentication information" }
Forbidden:
description: Forbidden (authenticated but no permission)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
examples:
forbid:
value: { code: "FORBIDDEN", message: "No permission to perform this operation" }
NotFound:
description: Resource not found (e.g., invalid movie title)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
examples:
missing:
value: { code: "NOT_FOUND", message: "Resource not found" }