#1382·grape

Modify the VENDOR_VERSION_HEADER_REGEX to support/recognize matches on the HAL (hal+json) format

Author: richddrCreated Apr 29, 2016Updated Apr 25, 2026
Labelsbug?

I have an endpoint which will only respond to hal format (application/hal+json) as specified in HAL's official page

Given the following:

ruby
class Foo < Grape::API
  version 'v1', using: :header, vendor: 'foo', strict: true, cascade: false
  content_type :hal, 'application/hal+json'

  format :hal
  formatter :hal, Grape::Formatter::Roar

  ...rest of code goes here...
end

Example Request: curl -H 'Accept: application/vnd.foo-v1+hal+json' http://www.foobar.com/api/foo

In /lib/grape/middleware/versioner/header.rb#, an_accept_header_with_version_and_vendor_is_present? returns false because the regex doesn't match against the full format which is hal+json

ruby
class Header < Base
        VENDOR_VERSION_HEADER_REGEX =
          /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))?(?:\+([a-z0-9*\-.]+))?\z/

        HAS_VENDOR_REGEX = /\Avnd\.[a-z0-9.\-_!#\$&\^]+/
        HAS_VERSION_REGEX = /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))+/

        def before
          strict_header_checks if strict?
          if media_type
            media_type_header_handler
          elsif headers_contain_wrong_vendor?
            fail_with_invalid_accept_header!('API vendor not found.')
          elsif headers_contain_wrong_version?
            fail_with_invalid_version_header!('API version not found.')
          end
        end

        private

        def strict_header_checks
          strict_accept_header_presence_check
          strict_version_vendor_accept_header_presence_check
        end

        def strict_accept_header_presence_check
          return unless header.qvalues.empty?
          fail_with_invalid_accept_header!('Accept header must be set.')
        end

        def strict_version_vendor_accept_header_presence_check
          return unless versions.present?
          return if an_accept_header_with_version_and_vendor_is_present?
          fail_with_invalid_accept_header!('API vendor or version not found.')
        end

        def an_accept_header_with_version_and_vendor_is_present?
          header.qvalues.keys.any? do |h|
            VENDOR_VERSION_HEADER_REGEX =~ h.sub('application/', '')
          end
        end
  ......
end

We'd need to modify VENDOR_VERSION_HEADER_REGEX to allow matching of these types of formats (hal+format)

I've modified the regex to allow match on said types:

OLD VENDOR_VERSION_HEADER_REGEX =

ruby
   /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))?(?:\+([a-z0-9*\-.]+))?\z/

image

NEW REGEX VENDOR_VERSION_HEADER_REGEX =

ruby
  /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))?(?:\+([a-z0-9*\-.+]+))+\z/

image

It'd be useful to add this change, so that grape supports the hal format out of the box without any custom work needed.