Make Gitlab::GrapeOpenapi::Generator a Singleton

Gitlab::GrapeOpenapi::Generator currently is intended to function as a Singleton in the gitlab-grape-openapi gem. However, there is nothing preventing people initializing multiple instances of the class in the future, thus breaking the assumption that the class functions as a Singleton.

Investigate whether it makes sense to enforce the Singleton pattern onto the class, e.g., by using Ruby's Singleton module, and if it does, implement the change.

Why This Matters

  • Prevents accidental misuse of the class by enforcing the singleton pattern at the language level.
  • Reduces maintenance burden by making the design intent explicit in code.
  • Eliminates potential bugs from multiple instances being created.

Acceptance Criteria

  • The Gitlab::GrapeOpenapi::Generator class uses Ruby's Singleton module or a similar solution that achieves the same result of enforcing the Singleton pattern
  • Multiple instantiation attempts return the same instance
  • Existing code that relies on the singleton behavior continues to work
  • Tests verify singleton behavior is enforced

OR

  • Justify in the comments the reason for NOT enforcing the Singleton pattern

Definition of Done

  • Code changes merged to gitlab-grape-openapi gem
  • All tests passing (new singleton tests + existing tests)
  • Documentation/comments updated if needed

Potential Risks / Considerations

  • Check if any code currently relies on creating multiple instances (unlikely but worth verifying)
  • Ensure thread-safety if the singleton is used in multi-threaded contexts

Resources

Analysis by Duo:

Advantages of implementing Singleton:

  1. Memory efficiency - Only one instance would exist, reducing memory overhead when generating OpenAPI specs multiple times across the application
  2. Consistent state - The @schema_registry and @tag_registry would be shared across all usages, preventing duplicate schema registrations
  3. Performance optimization - Entity and tag conversion could be cached and reused if the same API classes are processed multiple times
  4. Simplified access - No need to pass the generator instance around; could access via Generator.instance

Disadvantages of implementing Singleton:

  1. Testing complexity - Singleton state persists between tests, requiring explicit cleanup in test suites. The current spec creates fresh instances per test, which would break
  2. Thread safety concerns - The registries (@schema_registry, @tag_registry) would need synchronization mechanisms for concurrent access
  3. Configuration inflexibility - Currently accepts different api_classes and entity_classes per instantiation. Singleton would lock this to first initialization or require complex reset logic
  4. State pollution - Registries accumulate schemas/tags across multiple generate calls, potentially mixing unrelated API specifications
  5. Violates single responsibility - The class would manage both generation logic AND instance lifecycle
  6. Harder to parallelize - Cannot generate multiple independent OpenAPI specs simultaneously (e.g., for different API versions)

Current usage pattern benefits:

The current design where each generate call creates a fresh instance with clean registries is actually more appropriate for this use case because:

  * Each OpenAPI spec generation is independent
  * No shared state needed between generations
  * Tests remain isolated and predictable
  * Supports generating specs for different API class combinations
Edited by 🤖 GitLab Bot 🤖