From dae34fc2ca5e7fc1bb211125644855513f1972d9 Mon Sep 17 00:00:00 2001 From: teetangh Date: Thu, 14 Aug 2025 11:27:59 +0530 Subject: [PATCH] feat: Enhance Couchbase initialization and add hotel API endpoints - Improved Couchbase initialization with error handling for misconfigurations. - Added new API endpoints for hotel autocomplete and filtering in Swagger documentation. - Updated Swagger server URL to a more generic format. --- config/initializers/couchbase.rb | 145 +++++++++++++++++-------------- spec/swagger_helper.rb | 7 +- swagger/v1/swagger.yaml | 78 ++++++++++++++++- 3 files changed, 154 insertions(+), 76 deletions(-) diff --git a/config/initializers/couchbase.rb b/config/initializers/couchbase.rb index 7e10908..23f7b44 100644 --- a/config/initializers/couchbase.rb +++ b/config/initializers/couchbase.rb @@ -6,78 +6,91 @@ DB_CONN_STR = ENV['DB_CONN_STR'] DB_BUCKET_NAME = 'travel-sample' # Hardcoded bucket name -# Check if running in CI environment -if ENV['CI'] - # Use environment variables from GitHub Secrets - options = Couchbase::Cluster::ClusterOptions.new - options.authenticate(DB_USERNAME, DB_PASSWORD) - COUCHBASE_CLUSTER = Couchbase::Cluster.connect(DB_CONN_STR, options) -else - # Load environment variables from dev.env file - require 'dotenv' - Dotenv.load('dev.env') +begin + # Check if running in CI environment + if ENV['CI'] + # Use environment variables from GitHub Secrets + options = Couchbase::Cluster::ClusterOptions.new + options.authenticate(DB_USERNAME, DB_PASSWORD) + COUCHBASE_CLUSTER = Couchbase::Cluster.connect(DB_CONN_STR, options) + else + # Load environment variables from dev.env file + require 'dotenv' + Dotenv.load('dev.env') - # Define default values - DEFAULT_DB_USERNAME = 'Administrator' - DEFAULT_DB_PASSWORD = 'password' - DEFAULT_DB_CONN_STR = 'couchbase://localhost' + # Define default values + DEFAULT_DB_USERNAME = 'Administrator' + DEFAULT_DB_PASSWORD = 'password' + DEFAULT_DB_CONN_STR = 'couchbase://localhost' - # Get environment variables with fallback to default values - DB_USERNAME = ENV.fetch('DB_USERNAME', DEFAULT_DB_USERNAME) - DB_PASSWORD = ENV.fetch('DB_PASSWORD', DEFAULT_DB_PASSWORD) - DB_CONN_STR = ENV.fetch('DB_CONN_STR', DEFAULT_DB_CONN_STR) + # Get environment variables with fallback to default values + DB_USERNAME = ENV.fetch('DB_USERNAME', DEFAULT_DB_USERNAME) + DB_PASSWORD = ENV.fetch('DB_PASSWORD', DEFAULT_DB_PASSWORD) + DB_CONN_STR = ENV.fetch('DB_CONN_STR', DEFAULT_DB_CONN_STR) - # Connect to the Couchbase cluster - options = Couchbase::Cluster::ClusterOptions.new - options.authenticate(DB_USERNAME, DB_PASSWORD) - COUCHBASE_CLUSTER = Couchbase::Cluster.connect(DB_CONN_STR, options) -end + # Connect to the Couchbase cluster + options = Couchbase::Cluster::ClusterOptions.new + options.authenticate(DB_USERNAME, DB_PASSWORD) + COUCHBASE_CLUSTER = Couchbase::Cluster.connect(DB_CONN_STR, options) + end -# Open the bucket -bucket = COUCHBASE_CLUSTER.bucket(DB_BUCKET_NAME) + # Open the bucket + bucket = COUCHBASE_CLUSTER.bucket(DB_BUCKET_NAME) -# Open the default collection -default_collection = bucket.default_collection + # Open the default collection + default_collection = bucket.default_collection -# Create scope and collections if they don't exist -begin - scope = bucket.scope('inventory') -rescue Couchbase::Error::ScopeNotFoundError - bucket.create_scope('inventory') - scope = bucket.scope('inventory') -end + # Create scope and collections if they don't exist + begin + scope = bucket.scope('inventory') + rescue Couchbase::Error::ScopeNotFoundError + bucket.create_scope('inventory') + scope = bucket.scope('inventory') + end -begin - # create hotel search index - index_file_path = 'hotel_search_index.json' - index_content = File.read(index_file_path) - index_data = JSON.parse(index_content) - name = index_data["name"] - index = Couchbase::Management::SearchIndex.new - index.name= index_data["name"] - index.type= index_data["type"] - index.uuid= index_data["uuid"] if index_data.has_key?("uuid") - index.params= index_data["params"] if index_data.has_key?("params") - index.source_name= index_data["sourceName"] if index_data.has_key?("sourceName") - index.source_type= index_data["sourceType"] if index_data.has_key?("sourceType") - index.source_uuid= index_data["sourceUUID"] if index_data.has_key?("sourceUUID") - index.source_params= index_data["sourceParams"] if index_data.has_key?("sourceParams") - index.plan_params= index_data["planParams"] if index_data.has_key?("planParams") - scope.search_indexes.upsert_index(index) -rescue StandardError => err - #puts err.full_message -end + begin + # create hotel search index + index_file_path = 'hotel_search_index.json' + index_content = File.read(index_file_path) + index_data = JSON.parse(index_content) + name = index_data["name"] + index = Couchbase::Management::SearchIndex.new + index.name= index_data["name"] + index.type= index_data["type"] + index.uuid= index_data["uuid"] if index_data.has_key?("uuid") + index.params= index_data["params"] if index_data.has_key?("params") + index.source_name= index_data["sourceName"] if index_data.has_key?("sourceName") + index.source_type= index_data["sourceType"] if index_data.has_key?("sourceType") + index.source_uuid= index_data["sourceUUID"] if index_data.has_key?("sourceUUID") + index.source_params= index_data["sourceParams"] if index_data.has_key?("sourceParams") + index.plan_params= index_data["planParams"] if index_data.has_key?("planParams") + scope.search_indexes.upsert_index(index) + rescue StandardError => err + #puts err.full_message + end -%w[airline airport route].each do |collection_name| - scope.collection(collection_name) -rescue Couchbase::Error::CollectionNotFoundError - scope.create_collection(collection_name) -end + %w[airline airport route].each do |collection_name| + scope.collection(collection_name) + rescue Couchbase::Error::CollectionNotFoundError + scope.create_collection(collection_name) + end -# Scope is declared as constant to run FTS queries -INVENTORY_SCOPE = scope -INDEX_NAME = name -AIRLINE_COLLECTION = INVENTORY_SCOPE.collection('airline') -AIRPORT_COLLECTION = INVENTORY_SCOPE.collection('airport') -ROUTE_COLLECTION = INVENTORY_SCOPE.collection('route') -HOTEL_COLLECTION = INVENTORY_SCOPE.collection('hotel') + # Scope is declared as constant to run FTS queries + INVENTORY_SCOPE = scope + INDEX_NAME = name + AIRLINE_COLLECTION = INVENTORY_SCOPE.collection('airline') + AIRPORT_COLLECTION = INVENTORY_SCOPE.collection('airport') + ROUTE_COLLECTION = INVENTORY_SCOPE.collection('route') + HOTEL_COLLECTION = INVENTORY_SCOPE.collection('hotel') +rescue StandardError => err + # Allow Rails to boot even if Couchbase is not reachable/misconfigured + warn_msg = "Couchbase initialization skipped: #{err.class}: #{err.message}" + defined?(Rails) ? Rails.logger.warn(warn_msg) : warn(warn_msg) + COUCHBASE_CLUSTER = nil + INVENTORY_SCOPE = nil + INDEX_NAME = nil + AIRLINE_COLLECTION = nil + AIRPORT_COLLECTION = nil + ROUTE_COLLECTION = nil + HOTEL_COLLECTION = nil +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 35ddc71..6bb890b 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -25,12 +25,7 @@ paths: {}, servers: [ { - url: 'http://{defaultHost}', - variables: { - defaultHost: { - default: 'localhost:3000' - } - } + url: '/' } ], components: { diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 427089f..190fdc3 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -441,6 +441,79 @@ paths: type: string '400': description: bad request + "/api/v1/hotels/autocomplete": + get: + summary: Retrieve suggestion for Hotel names + tags: + - Hotels + parameters: + - name: name + in: query + description: name of the hotel + schema: + type: string + responses: + '200': + description: No suggestion + content: + application/json: + schema: + type: Array + items: + type: string + "/api/v1/hotels/filter": + post: + summary: Hotel search filter + tags: + - Hotels + parameters: [] + responses: + '200': + description: only one Hotels found + content: + application/json: + schema: + type: Array + items: + type: object + properties: + name: + type: string + title: + type: string + description: + type: string + country: + type: string + city: + type: string + nullable: true + state: + type: string + nullable: true + required: + - name + - title + - description + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + title: + type: string + description: + type: string + country: + type: string + city: + type: string + state: + type: string + description: hotel filter "/api/v1/routes/{id}": get: summary: Retrieves a route by ID @@ -619,10 +692,7 @@ paths: '404': description: route not found servers: -- url: http://{defaultHost} - variables: - defaultHost: - default: localhost:3000 +- url: "/" components: schemas: Airline: