feat: add public read-only places API (#123) - #137
Merged
Conversation
GET /api/places exposes the merged data/places/*.json dataset programmatically, so anything can build on top of it without cloning the repo. Reuses the existing record contract (data/places.schema.json) rather than inventing a second one. - Filters: `city` (case-insensitive, slug-normalized like the city pages) and `category` (one of the six PLACE_TYPES). Unknown categories, empty or repeated values, and malformed limit/offset return 400 with a message — never silently ignored. - Pagination: default limit 100, hard maximum 500 (values above are clamped, not dumped), zero-based `offset`, and `total` reflecting the full match set before slicing. - The `country` filter is rejected with an explicit 400: the schema has no country field, so no record could satisfy it. Flagged for maintainer input rather than inventing a city->country mapping. - Headers: permissive CORS (Access-Control-Allow-Origin: *) and cache headers matching reality (dataset changes a few times a week: 6h ISR revalidate + stale-while-revalidate). - Docs: new /docs/places-api page (registered in the Developers group) documenting the shape, filters, pagination, and errors, linking the schema. 76 vitest tests (24 new: full parse/query contract unit tests plus end-to-end route-handler tests covering the issue's own verification examples), eslint clean, next build clean with /api/places and /docs/places-api both emitted. Closes StudentSuite#123
Contributor
|
@aryansk is attempting to deploy a commit to the studentsuite Team on Vercel. A member of the Team first needs to authorize it. |
yakew7
marked this pull request as ready for review
August 15, 2026 14:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
GET /api/placesexposes the mergeddata/places/*.jsondataset read-only, so consumers can build on top of it without cloning the repo. Per the issue's "document the existing contract rather than inventing a second one", records are exactly the schema'sPlaceshape — no new fields, no wrappers.Filters —
city(case-insensitive; spaces/hyphens normalize to the dataset's underscore slugs, soNew Delhimatchesnew delhi) andcategory(one of the sixPLACE_TYPES). Unknown category, empty/repeated params, and malformedlimit/offsetreturn 400 with a message — never silently ignored.Pagination — default
limit100, hard max 500, values above clamped (per the issue's own verification example), zero-basedoffset, andtotal= matches before slicing so consumers can page to the end.Headers — permissive CORS (
Access-Control-Allow-Origin: *) and cache headers matching reality (dataset changes a few times a week): 6h ISRrevalidate+Cache-Control: public, max-age=3600, s-maxage=21600, stale-while-revalidate=86400.Docs — new
/docs/places-apipage in the Developers group: shape, filters, pagination, errors, and a link todata/places.schema.json.One decision to flag:
countryThe issue lists a
countryfilter, but the dataset has no country field — the schema isid/name/type/city/lat/lng/address/gmaps_link/added_by(+ optionalverified/exam/valid_till), and none of the 328 records across 217 cities carry one. Rather than invent a city→country mapping (guesswork for ambiguous cities likespringfield/reading, and a second contract the issue warns against), the API rejectscountrywith an explicit 400 explaining the gap and pointing at the docs. The alternative — silently returning everything — seemed worse.If you'd like country filtering, the cleanest path is adding a
countryfield to the schema + dataset (the API'scountrybranch is a one-line change then), or a maintainer-endorsed city→country table. Happy to implement either if you tell me which.Verification
countrydecision) plus end-to-end route-handler tests hitting the realGEThandler — including the issue's own examples (?city=Mumbai&limit=5,?limit=999999clamps).npx eslintclean on changed files,npm run buildclean — both/api/placesand/docs/places-apiemitted (I also verified the route handler in-process: status codes, CORS + cache headers, filters, clamp, 400s).Closes #123