Back to Repositories

Testing Route Parameter Requirements with Dots in Grape API

This test suite examines Grape API’s routing capabilities with complex parameter requirements, specifically focusing on handling dots in route parameters. It validates both namespace and path parameter handling with custom regex requirements, ensuring proper URL parsing and parameter extraction.

Test Coverage Overview

The test suite provides comprehensive coverage of Grape’s route parameter handling with dots:
  • Namespace parameters containing dots
  • Multiple path parameters with dots
  • Combined namespace and path parameters
  • Requirement overriding and merging scenarios
Each test case validates both the response status and parameter extraction accuracy.

Implementation Analysis

The testing approach uses RSpec to verify Grape’s routing functionality through direct HTTP requests. It employs a pattern of defining routes with custom requirements using regular expressions, specifically %r{[^/]+}, to allow dots while preventing path segment conflicts.

The implementation demonstrates both isolated parameter testing and combined parameter scenarios with requirement inheritance.

Technical Details

Testing tools and configuration:
  • RSpec as the testing framework
  • Grape::API class inheritance for route definition
  • Regular expressions for parameter requirements
  • HTTP GET request testing
  • Response status and body validation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Isolated test cases for specific functionality
  • Clear test case organization within contexts
  • Consistent validation patterns
  • Progressive complexity in test scenarios
  • Thorough validation of both success status and response content

ruby-grape/grape

spec/grape/api/routes_with_requirements_spec.rb

            
# frozen_string_literal: true

describe Grape::Endpoint do
  subject { Class.new(Grape::API) }

  def app
    subject
  end

  context 'get' do
    it 'routes to a namespace param with dots' do
      subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
        get '/' do
          params[:ns_with_dots]
        end
      end

      get '/test.id.with.dots'
      expect(last_response.status).to eq 200
      expect(last_response.body).to eq 'test.id.with.dots'
    end

    it 'routes to a path with multiple params with dots' do
      subject.get ':id_with_dots/:another_id_with_dots', requirements: { id_with_dots: %r{[^/]+},
                                                                         another_id_with_dots: %r{[^/]+} } do
        "#{params[:id_with_dots]}/#{params[:another_id_with_dots]}"
      end

      get '/test.id/test2.id'
      expect(last_response.status).to eq 200
      expect(last_response.body).to eq 'test.id/test2.id'
    end

    it 'routes to namespace and path params with dots, with overridden requirements' do
      subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
        get ':another_id_with_dots',     requirements: { ns_with_dots: %r{[^/]+},
                                                         another_id_with_dots: %r{[^/]+} } do
          "#{params[:ns_with_dots]}/#{params[:another_id_with_dots]}"
        end
      end

      get '/test.id/test2.id'
      expect(last_response.status).to eq 200
      expect(last_response.body).to eq 'test.id/test2.id'
    end

    it 'routes to namespace and path params with dots, with merged requirements' do
      subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
        get ':another_id_with_dots',     requirements: { another_id_with_dots: %r{[^/]+} } do
          "#{params[:ns_with_dots]}/#{params[:another_id_with_dots]}"
        end
      end

      get '/test.id/test2.id'
      expect(last_response.status).to eq 200
      expect(last_response.body).to eq 'test.id/test2.id'
    end
  end
end