diff --git a/Gemfile b/Gemfile index c8fbf0a..9bae0aa 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,6 @@ gem "stimulus-rails" # Build JSON APIs with ease [https://github.com/rails/jbuilder] gem "jbuilder" gem "grape" -gem "grape-swagger" gem "rswag-ui" gem "caxlsx" gem "caxlsx_rails" diff --git a/Gemfile.lock b/Gemfile.lock index ee537f5..dc9143d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -120,9 +120,6 @@ GEM docile (1.4.1) dotenv (3.2.0) drb (2.2.3) - dry-configurable (1.3.0) - dry-core (~> 1.1) - zeitwerk (~> 2.6) dry-core (1.2.0) concurrent-ruby (~> 1.0) logger @@ -151,15 +148,12 @@ GEM raabro (~> 1.4) globalid (1.3.0) activesupport (>= 6.1) - grape (3.1.1) - activesupport (>= 7.1) - dry-configurable + grape (2.4.0) + activesupport (>= 6.1) dry-types (>= 1.1) mustermann-grape (~> 1.1.0) rack (>= 2) zeitwerk - grape-swagger (2.1.3) - grape (>= 1.7, < 4.0) htmlentities (4.4.2) i18n (1.14.8) concurrent-ruby (~> 1.0) @@ -178,7 +172,7 @@ GEM jbuilder (2.14.1) actionview (>= 7.0.0) activesupport (>= 7.0.0) - json (2.18.0) + json (2.18.1) kamal (2.10.1) activesupport (>= 7.0) base64 (~> 0.2) @@ -426,7 +420,6 @@ DEPENDENCIES caxlsx_rails debug grape - grape-swagger image_processing (~> 1.2) importmap-rails jbuilder @@ -487,7 +480,6 @@ CHECKSUMS docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e dotenv (3.2.0) sha256=e375b83121ea7ca4ce20f214740076129ab8514cd81378161f11c03853fe619d drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373 - dry-configurable (1.3.0) sha256=882d862858567fc1210d2549d4c090f34370fc1bb7c5c1933de3fe792e18afa8 dry-core (1.2.0) sha256=0cc5a7da88df397f153947eeeae42e876e999c1e30900f3c536fb173854e96a1 dry-inflector (1.3.1) sha256=7fb0c2bb04f67638f25c52e7ba39ab435d922a3a5c3cd196120f63accb682dcc dry-logic (1.6.0) sha256=da6fedbc0f90fc41f9b0cc7e6f05f5d529d1efaef6c8dcc8e0733f685745cea2 @@ -499,8 +491,7 @@ CHECKSUMS ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f fugit (1.12.1) sha256=5898f478ede9b415f0804e42b8f3fd53f814bd85eebffceebdbc34e1107aaf68 globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11 - grape (3.1.1) sha256=774f16782d917a90e69de0499dfaab571e5ad967569ac066a2b0b918af12de69 - grape-swagger (2.1.3) sha256=9ee955ada77c10ea2f2d2da5edcc4fc3cddcc40a6936f1b2558ee7b44e0f1153 + grape (2.4.0) sha256=3d59673e80f11d49ba86270b78344e5348dc057b318c2bbc1c01f3532f9b6aec htmlentities (4.4.2) sha256=bbafbdf69f2eca9262be4efef7e43e6a1de54c95eb600f26984f71d2fe96c5c3 i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 image_processing (1.14.0) sha256=754cc169c9c262980889bec6bfd325ed1dafad34f85242b5a07b60af004742fb @@ -508,7 +499,7 @@ CHECKSUMS io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806 jbuilder (2.14.1) sha256=4eb26376ff60ef100cb4fd6fd7533cd271f9998327e86adf20fd8c0e69fabb42 - json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505 + json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986 kamal (2.10.1) sha256=53b7ecb4c33dd83b1aedfc7aacd1c059f835993258a552d70d584c6ce32b6340 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 diff --git a/app/controllers/api/base.rb b/app/controllers/api/base.rb index b9de713..f5c6f80 100644 --- a/app/controllers/api/base.rb +++ b/app/controllers/api/base.rb @@ -1,8 +1,9 @@ require "grape" -require "grape-swagger" +require "ostruct" class Api::Base < Grape::API format :json + default_format :json content_type :json, "application/json" helpers do @@ -17,9 +18,7 @@ class Api::Base < Grape::API resource :entries do desc "Return public entries in all languages", - is_array: true, - success: Api::Entities::Entry, - produces: [ "application/json" ] + attributes: OpenStruct.new(success: nil, produces: nil) params do optional :since, type: String, @@ -46,14 +45,4 @@ class Api::Base < Grape::API ) end end - - add_swagger_documentation( - info: { - title: "Sanasto Wiki API", - description: "Public sync API for Sanasto Wiki glossary entries." - }, - mount_path: "/swagger", - hide_documentation_path: true, - format: :json - ) end diff --git a/app/controllers/api/entities/entry.rb b/app/controllers/api/entities/entry.rb deleted file mode 100644 index 03e8968..0000000 --- a/app/controllers/api/entities/entry.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Api - module Entities - class Entry < Grape::Entity - expose :id, documentation: { type: "integer", format: "int64", desc: "Entry ID." } - expose :category, documentation: { type: "string", desc: "Category label." } - expose :fi, documentation: { type: "string", desc: "Finnish term/definition.", allow_nil: true } - expose :en, documentation: { type: "string", desc: "English term/definition.", allow_nil: true } - expose :sv, documentation: { type: "string", desc: "Swedish term/definition.", allow_nil: true } - expose :no, documentation: { type: "string", desc: "Norwegian term/definition.", allow_nil: true } - expose :ru, documentation: { type: "string", desc: "Russian term/definition.", allow_nil: true } - expose :de, documentation: { type: "string", desc: "German term/definition.", allow_nil: true } - expose :updated_at, documentation: { type: "string", format: "date-time", desc: "Last update timestamp (ISO8601)." } - end - end -end diff --git a/app/controllers/api/swagger_controller.rb b/app/controllers/api/swagger_controller.rb new file mode 100644 index 0000000..61f2946 --- /dev/null +++ b/app/controllers/api/swagger_controller.rb @@ -0,0 +1,119 @@ +# config/routes.rb + +# app/controllers/api/swagger_controller.rb +module Api + class SwaggerController < ApplicationController + def index + render json: { + openapi: "3.0.0", + info: { + title: "Sanasto Wiki API", + description: "Public sync API for Sanasto Wiki glossary entries.", + version: "1.0.0" + }, + servers: [ + { + url: "https://#{request.host}", + description: "Production server" + } + ], + paths: { + "/api/entries": { + get: { + summary: "Return public entries in all languages", + description: "Retrieve all active glossary entries with optional filtering by update timestamp", + tags: [ "Entries" ], + parameters: [ + { + name: "since", + in: "query", + description: "ISO8601 timestamp. Returns entries updated after this time.", + required: false, + schema: { + type: "string", + format: "date-time", + example: "2024-01-01T00:00:00Z" + } + } + ], + responses: { + "200": { + description: "List of entries", + content: { + "application/json": { + schema: { + type: "array", + items: { + "$ref": "#/components/schemas/Entry" + } + } + } + } + }, + "400": { + description: "Invalid since parameter", + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { type: "string" } + } + } + } + } + } + } + } + } + }, + components: { + schemas: { + Entry: { + type: "object", + properties: { + id: { + type: "integer", + description: "Entry ID" + }, + category: { + type: "string", + description: "Entry category" + }, + fi: { + type: "string", + description: "Finnish translation" + }, + en: { + type: "string", + description: "English translation" + }, + sv: { + type: "string", + description: "Swedish translation" + }, + no: { + type: "string", + description: "Norwegian translation" + }, + ru: { + type: "string", + description: "Russian translation" + }, + de: { + type: "string", + description: "German translation" + }, + updated_at: { + type: "string", + format: "date-time", + description: "Last update timestamp (ISO8601)" + } + } + } + } + } + } + end + end +end diff --git a/config/routes.rb b/config/routes.rb index b6a2f85..59af918 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,10 @@ Rails.application.routes.draw do # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + mount Api::Base => "/api" + get "/api/swagger", to: "api/swagger#index" + mount Rswag::Ui::Engine => "/api" + # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Can be used by load balancers and uptime monitors to verify that the app is live. get "up" => "rails/health#show", as: :rails_health_check @@ -51,9 +55,6 @@ Rails.application.routes.draw do end end - mount Api::Base => "/api" - mount Rswag::Ui::Engine => "/api" - resources :entries do resources :comments, only: [ :create ] collection do