# frozen_string_literal: true require "sinatra" require "puma" require "route_downcaser" require "prometheus/middleware/collector" require "prometheus/middleware/exporter" require_relative "server_utils" # Server with endpoints generated based on Entities with CRUD operations for them class RestServer < Sinatra::Base set :server, :puma enable :logging if ENV["debug"] == "true" set :bind, "0.0.0.0" use RouteDowncaser::DowncaseRouteMiddleware use Prometheus::Middleware::Collector use Prometheus::Middleware::Exporter helpers ServerUtils before do @request_id = SecureRandom.uuid headers["X-Correlation-Id"] = @request_id headers["Access-Control-Allow-Origin"] = "*" log({ msg: "Request" }) if request.fullpath != "" end after do log({ msg: "Response", status: response.status }) if request.fullpath != "" end get "/favicon.ico" do send_file File.join(__dir__, "rest.ico") end SWAGGER_FILES = %w[index.css swagger.html swagger-initializer.js swagger-ui-bundle.js swagger-ui-standalone-preset.js swagger-ui.css].freeze SWAGGER_FILES.each do |filename| get "/#{filename.gsub(".html", "")}" do if filename.end_with? ".json" content_type :json elsif filename.end_with? ".css" content_type :css elsif filename.end_with? ".js" content_type :js end File.read(File.join(__dir__, "swagger", filename)) end end get "/swagger.json" do content_type :json SwaggerBuilder.build_swagger_for(Entities.models, request.host_with_port) end get "/" do summary = { models: Entities.models.keys.to_s, docs_url: "Swagger docs" } summary[:db] = MongoClient.client.options if ENV["mongodb"] summary.to_json rescue StandardError => e [500, e.message] end Entities.models.each_key do |model| post "/#{model.downcase}" do content_type :json request_body = request.body.read data = {} data = JSON.parse(request_body) unless request_body.empty? id = "" if data["id"] id = data["id"].to_s else id = SecureRandom.uuid data["id"] = id end if ENV["mongodb"] MongoClient.insert(model, data, id) else Entities.models[model][id] = data end log({ msg: "Created #{id}" }) [201, JSON.generate({ id: id })] end options "/#{model.downcase}" do response["Allow"] = "*" response["Access-Control-Allow-Methods"] = "*" response["Access-Control-Allow-Headers"] = "*" end get "/#{model.downcase}" do content_type :json if ENV["mongodb"] MongoClient.find_all(model, params).to_json else matching_values = Entities.find_all(model, params) return matching_values.to_json end rescue StandardError => e [404, "Nothing found using #{params}. Only first param considered. #{e.message}"] end get "/#{model.downcase}/:id" do |id| content_type :json if ENV["mongodb"] results = MongoClient.find(model, id) return not_have(id) unless results.first results.first.to_json else return not_have(id) unless id?(model, id) Entities.models[model][id].to_json end end options "/#{model.downcase}/:id" do response["Allow"] = "*" response["Access-Control-Allow-Origin"] = "*" response["Access-Control-Allow-Methods"] = "*" response["Access-Control-Allow-Headers"] = "*" end put "/#{model.downcase}/:id" do |id| content_type :json data = JSON.parse(request.body.read) if ENV["mongodb"] results = MongoClient.find(model, id) return not_have(id) unless results.first MongoClient.update(model, id, data) else return not_have(id) unless id?(model, id) Entities.models[model][id] = data end 204 end delete "/#{model.downcase}/:id" do |id| content_type :json if ENV["mongodb"] results = MongoClient.find(model, id) return not_have(id) unless results.first MongoClient.delete(model, id) else return not_have(id) unless id?(model, id) Entities.models[model].delete(id) end 204 end end end