grape icon indicating copy to clipboard operation
grape copied to clipboard

Add custom headers to all apis in swagger doc

Open chiwenchen opened this issue 4 years ago • 7 comments

there is a way to add headers field in one api as document mentions, like below

class API::V1::Teachers < Grape::API
  resource :teachers do
    desc "get all teachers information" do
      headers XAuthToken: {
            description: 'Validates your identity',
            required: true
          },
          XOptionalHeader: {
            description: 'Not really needed',
            required: false
          }
    end
    success: API::V1::Entities::Teachers::Base
    get '' do
      teachers = Teacher.all

      present :teachers, teachers, with: API::V1::Entities::Teachers::Base
    end
  end
end

but is there a way to add same headers to all apis under certain resources or namespace or all of them?

chiwenchen avatar Oct 16 '20 02:10 chiwenchen

I don't think so, but it would be nice if we extended all keywords, including what's inside desc, similarly to params with use:. I think I'd like to be able to write:

class API::V1::Teachers < Grape::API
  helpers do
    headers :auth do
      XAuthToken: {
            description: 'Validates your identity',
            required: true
          },
          XOptionalHeader: {
            description: 'Not really needed',
            required: false
          }
    end
  end
  resource :teachers do
    desc "get all teachers information" do
      headers :auth
    end
    success: API::V1::Entities::Teachers::Base
    get '' do
      teachers = Teacher.all
      present :teachers, teachers, with: API::V1::Entities::Teachers::Base
    end
  end
end

That said, maybe it's an overkill. I think you can just do this:

class API::V1::Teachers < Grape::API
  AUTH_HEADERS = {
          XAuthToken: {
            description: 'Validates your identity',
            required: true
          },
          XOptionalHeader: {
            description: 'Not really needed',
            required: false
          }
    }
  end
  resource :teachers do
    desc "get all teachers information" do
      headers AUTH_HEADERS
    end
    success: API::V1::Entities::Teachers::Base
    get '' do
      teachers = Teacher.all
      present :teachers, teachers, with: API::V1::Entities::Teachers::Base
    end
  end
end

I'll leave this open as a feature request for the use: scenario.

dblock avatar Oct 16 '20 12:10 dblock

Another idea is to define authenticated_resource that will call resource and add those headers.

dblock avatar Oct 16 '20 12:10 dblock

@dblock what about something like default desc? It seems to me it would solve the problem of the current issue with repeating auth headers, but also will allow following DRY more precisely. For example, sometimes I'd like to mark the entire resource with the same tags, mark it deprecated or hide it. With default desc it could be quite easy.

Koilanetroc avatar Sep 22 '21 01:09 Koilanetroc

It's a good idea @Koilanetroc but would have to look at a PR to be sure.

dblock avatar Sep 22 '21 13:09 dblock

Okay, I'll try to implement this if you don't mind

Koilanetroc avatar Sep 23 '21 02:09 Koilanetroc

@dblock could you please explain what is line namespace_setting :description, options for? It's in lib/grape/dsl/desc.rb#79

      def desc(description, options = {}, &config_block)
        if block_given?
          endpoint_configuration = if defined?(configuration)
                                     # When the instance is mounted - the configuration is executed on mount time
                                     if configuration.respond_to?(:evaluate)
                                       configuration.evaluate
                                     # Within `given` or `mounted blocks` the configuration is already evaluated
                                     elsif configuration.is_a?(Hash)
                                       configuration
                                     end
                                   end
          endpoint_configuration ||= {}
          config_class = desc_container(endpoint_configuration)

          config_class.configure do
            description description
          end

          config_class.configure(&config_block)
          unless options.empty?
            warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.'
          end
          options = config_class.settings
        else
          options = options.merge(description: description)
        end

        namespace_setting :description, options # <---------------- this one
        route_setting :description, options
      end

It receives same options as route_setting, but I haven't understood for what. Specs didn't say anything usefull(just check namespace_setting :description, options was performed). I checked the full process of desc creating, but haven't found a case when this line changes desc in any way.

Was it added for sharing desc for all routes inside namespace? Will be grateful for any hint.

Koilanetroc avatar Oct 01 '21 01:10 Koilanetroc

I bet there's "history" rather than a reason for this one. I don't remember. Maybe git blame it back to a PR?

dblock avatar Oct 02 '21 14:10 dblock