Skip to content

Add Ruby Sinatra PostgreSQL quickstart application - #1

Open
Nsanjayboruds wants to merge 6 commits into
keploy:mainfrom
Nsanjayboruds:add-ruby-quickstart
Open

Add Ruby Sinatra PostgreSQL quickstart application#1
Nsanjayboruds wants to merge 6 commits into
keploy:mainfrom
Nsanjayboruds:add-ruby-quickstart

Conversation

@Nsanjayboruds

Copy link
Copy Markdown

Description

This PR introduces a comprehensive Ruby (Sinatra) + PostgreSQL sample application for the Keploy quickstart guides.

As discussed in keploy/docs#773, this application goes beyond a basic CRUD structure to provide a much more realistic scenario that better showcases Keploy's capabilities in a real-world environment.

Key Features Implemented

  • Advanced Application Logic:
    • The Books API now supports complex query patterns including search, filtering (by author/year), sorting, and pagination.
    • Added a dependent Reviews resource to demonstrate how Keploy handles related database tables and foreign keys.
    • Implemented an analytics endpoint (/analytics/books/top-rated) to showcase complex SQL aggregations.
    • Robust input validation and error handling (400/404 cases) throughout the API.
  • Automated Traffic Script (run-keploy.sh):
    • Developed a bash script that automatically starts Keploy in record mode alongside the Docker containers.
    • The script generates exactly 20 diverse API calls, executing end-to-end flows that cover both positive scenarios (creating, updating, fetching resources) and negative scenarios (validation errors, fetching non-existent IDs).
  • Easy Setup: Included docker-compose.yml for seamless containerized execution, along with local setup instructions in the README.md.

Related PR

  • Updates the official documentation in the main docs repo: keploy/docs#773

How to Test

  1. Clone this branch and navigate to sinatra-postgres-quickstart.
  2. Run the automated Keploy recording script:
    ./run-keploy.sh
  3. Observe the script successfully generate 20 API calls and capture the test cases + mocks in the /keploy directory.
  4. Run the replay to verify the recorded test suite passes:
    keploy test -c "docker compose up" --container-name "ruby-books-app" --cmd-type docker-compose

@dhananjay6561

Copy link
Copy Markdown
Member

hi @Nsanjayboruds please make sure DCO check passes by using -s flag while writing a commit message

Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>

@dhananjay6561 dhananjay6561 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together Nishant, the breadth here is genuinely nice: search, filtering, pagination, a dependent reviews resource, an analytics aggregate, and a scripted record run of 20 requests that covers both happy and error paths. The SQL is parameterized throughout, and the sort_by and order inputs are mapped through allowlists before they touch the query, which is exactly the right way to keep it safe from injection.

One blocker before this can go in: app.rb does not currently parse. Running ruby -c app.rb reports syntax error, unexpected end-of-input at line 886. It looks like two versions of the app got merged into a single file, so almost every route is defined twice and the top section (the first health route plus the helpers block) is spliced together mid block. As it stands the app will not boot, so the record and replay flow cannot run.

I left inline notes on the specific spots. The main fix is to regenerate app.rb from the one intended version (the refactored routes that use halt_json and the helper methods read clean and complete), delete the older duplicate blocks, and confirm ruby -c app.rb passes and the container actually starts before pushing again. A few smaller design notes are inline too, none of those are blocking. Happy to take another look as soon as it is regenerated.

Comment thread sinatra-postgres-quickstart/app.rb Outdated
Comment thread sinatra-postgres-quickstart/app.rb Outdated
Comment thread sinatra-postgres-quickstart/app.rb Outdated
Comment thread sinatra-postgres-quickstart/app.rb Outdated
Comment thread sinatra-postgres-quickstart/app.rb
Comment thread sinatra-postgres-quickstart/app.rb
Comment thread sinatra-postgres-quickstart/app.rb Outdated
Comment thread sinatra-postgres-quickstart/.gitignore
Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>
…g, lockfile)

Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>
@Nsanjayboruds

Copy link
Copy Markdown
Author

Thanks for putting this together Nishant, the breadth here is genuinely nice: search, filtering, pagination, a dependent reviews resource, an analytics aggregate, and a scripted record run of 20 requests that covers both happy and error paths. The SQL is parameterized throughout, and the sort_by and order inputs are mapped through allowlists before they touch the query, which is exactly the right way to keep it safe from injection.

One blocker before this can go in: app.rb does not currently parse. Running ruby -c app.rb reports syntax error, unexpected end-of-input at line 886. It looks like two versions of the app got merged into a single file, so almost every route is defined twice and the top section (the first health route plus the helpers block) is spliced together mid block. As it stands the app will not boot, so the record and replay flow cannot run.

I left inline notes on the specific spots. The main fix is to regenerate app.rb from the one intended version (the refactored routes that use halt_json and the helper methods read clean and complete), delete the older duplicate blocks, and confirm ruby -c app.rb passes and the container actually starts before pushing again. A few smaller design notes are inline too, none of those are blocking. Happy to take another look as soon as it is regenerated.


Thanks so much for the detailed review, @dhananjay6561 !

I've just pushed the updates to address all of your points:

  1. app.rb Cleanup: I regenerated the file completely from the clean version. The syntax error is gone, the duplicate route blocks have been removed, and the validate_numeric_id NameError is resolved (the routes now properly use valid_positive_integer?).
  2. Database Initialization Fix: SCHEMA_SQL execution has been moved out of db_connection and now runs safely in an initialization block at application startup.
  3. Payload Validation: Added the .is_a?(Hash) type-check guard right after parsing the JSON body to ensure clean 400 errors for unexpected top-level types.
  4. Error Hiding: Refactored the 500 and 503 handlers to return generic error messages, preventing raw database messages from leaking.
  5. Lockfile Tracking: Removed Gemfile.lock from .gitignore so that Docker and local environments can resolve the exact same gem versions predictably.

@dhananjay6561 dhananjay6561 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround Nishant, this is a big step up. I went back through it and confirmed the main points are sorted: app.rb parses cleanly now (ruby -c passes) and every route is defined exactly once, so the duplicated merge blocks are gone. The old validate_numeric_id calls are all pointing at valid_positive_integer?, the schema runs once at startup instead of on every request, non object JSON bodies are guarded with the is_a?(Hash) check, the raw database error is no longer handed back to clients, and Gemfile.lock is out of .gitignore.

The rest reads well too. SQL stays parameterized, the sort_by and order inputs go through allowlists before hitting the query, the ISBN uniqueness check is backed by the database constraint with a rescue so the race is covered, and the validation across books and reviews lines up with the negative paths the record script exercises.

Approving. I left one tiny optional note on the health endpoint, nothing blocking. Nice work getting this cleaned up.

Comment thread sinatra-postgres-quickstart/app.rb
Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>
Copilot AI lite review requested due to automatic review settings September 1, 2026 05:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new Sinatra + PostgreSQL “Books + Reviews” sample application intended for Keploy quickstart documentation, including Docker-based setup and an automated recording script that generates a 20-request scenario.

Changes:

  • Introduces a Sinatra API implementing books, dependent reviews, and an analytics endpoint, backed by PostgreSQL.
  • Adds Docker assets (Dockerfile, compose files) and database initialization SQL for an easy, containerized run.
  • Adds Keploy configuration plus an automation script (run-keploy.sh) to record a deterministic 20-call traffic flow.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
sinatra-postgres-quickstart/app.rb Implements the Sinatra API, DB access, validation, and analytics endpoint.
sinatra-postgres-quickstart/init.sql Creates tables/indexes and seeds initial sample data for Postgres.
sinatra-postgres-quickstart/docker-compose.yml Defines app + Postgres services for the main Docker run.
sinatra-postgres-quickstart/docker-compose.yml.test Adds a separate compose setup intended for test usage.
sinatra-postgres-quickstart/Dockerfile Builds the Ruby app container and starts Puma.
sinatra-postgres-quickstart/Gemfile Declares Ruby/Sinatra/Postgres dependencies.
sinatra-postgres-quickstart/config.ru Rack entrypoint to run the Sinatra app.
sinatra-postgres-quickstart/run-keploy.sh Automates Keploy record mode and generates 20 API calls.
sinatra-postgres-quickstart/keploy.yml Adds a Keploy configuration file for record/replay defaults.
sinatra-postgres-quickstart/README.md Documents setup, endpoints, and the Keploy record/replay workflow.
sinatra-postgres-quickstart/.gitignore Ignores Keploy output and common Ruby/local artifacts.
Suppressed comments (1)

sinatra-postgres-quickstart/app.rb:61

  • On schema init failure, the app only prints a message and continues, which can leave the container "running" but non-functional. Consider failing fast and adding a next-step hint (e.g., check DB_HOST/DB_PORT and Postgres readiness) to make the failure actionable.
rescue PG::Error => e
  puts "Failed to initialize database schema: #{e.message}"
end

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sinatra-postgres-quickstart/run-keploy.sh
Comment thread sinatra-postgres-quickstart/app.rb
Comment thread sinatra-postgres-quickstart/app.rb
Comment thread sinatra-postgres-quickstart/README.md
Comment thread sinatra-postgres-quickstart/keploy.yml
Comment thread sinatra-postgres-quickstart/keploy.yml Outdated
Comment thread sinatra-postgres-quickstart/keploy.yml Outdated
…check

Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>
…dType, correct spelling)

Signed-off-by: Nsanjayboruds <nishantborude555@gmail.com>
@Nsanjayboruds

Copy link
Copy Markdown
Author

Thanks for the quick turnaround Nishant, this is a big step up. I went back through it and confirmed the main points are sorted: app.rb parses cleanly now (ruby -c passes) and every route is defined exactly once, so the duplicated merge blocks are gone. The old validate_numeric_id calls are all pointing at valid_positive_integer?, the schema runs once at startup instead of on every request, non object JSON bodies are guarded with the is_a?(Hash) check, the raw database error is no longer handed back to clients, and Gemfile.lock is out of .gitignore.

The rest reads well too. SQL stays parameterized, the sort_by and order inputs go through allowlists before hitting the query, the ISBN uniqueness check is backed by the database constraint with a rescue so the race is covered, and the validation across books and reviews lines up with the negative paths the record script exercises.

Approving. I left one tiny optional note on the health endpoint, nothing blocking. Nice work getting this cleaned up.

Thanks so much for the approval and the helpful review! I actually went ahead and implemented that optional fix for /health too. It now uses its own raw PG.connect check so it accurately returns a 503 instead of falling back to 500 when the database is entirely down.

@Nsanjayboruds

Copy link
Copy Markdown
Author

Thanks for the quick turnaround Nishant, this is a big step up. I went back through it and confirmed the main points are sorted: app.rb parses cleanly now (ruby -c passes) and every route is defined exactly once, so the duplicated merge blocks are gone. The old validate_numeric_id calls are all pointing at valid_positive_integer?, the schema runs once at startup instead of on every request, non object JSON bodies are guarded with the is_a?(Hash) check, the raw database error is no longer handed back to clients, and Gemfile.lock is out of .gitignore.
The rest reads well too. SQL stays parameterized, the sort_by and order inputs go through allowlists before hitting the query, the ISBN uniqueness check is backed by the database constraint with a rescue so the race is covered, and the validation across books and reviews lines up with the negative paths the record script exercises.
Approving. I left one tiny optional note on the health endpoint, nothing blocking. Nice work getting this cleaned up.

Thanks so much @dhananjay6561 for the approval and the helpful review! I actually went ahead and implemented that optional fix for /health too. It now uses its own raw PG.connect check so it accurately returns a 503 instead of falling back to 500 when the database is entirely down.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants