Skip to content

Commit 552bf65

Browse files
committed
Add support for running as a Rack app
This makes it so that users of the gem can optionally run the app as a Rack app, making it easy to mount within a Rails or Sinatra app. Reasons why would be to add authentication or have a nicer developer experience instead of regenerating the docs over and over again. Fixes #102
1 parent 2adfed8 commit 552bf65

File tree

8 files changed

+756
-11
lines changed

8 files changed

+756
-11
lines changed

README.md

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ gem install graphql-docs
2424

2525
## Usage
2626

27+
GraphQLDocs provides two ways to serve your documentation:
28+
29+
1. **Static Site Generator (SSG)** - Pre-generate all HTML files (default)
30+
2. **Rack Application** - Serve documentation dynamically on-demand
31+
32+
### Static Site Generation (SSG)
33+
2734
GraphQLDocs can be used as a Ruby library to build the documentation website. Using it as a Ruby library allows for more control and using every supported option. Here's an example:
2835

2936
```ruby
@@ -54,6 +61,110 @@ See all of the supported CLI options with:
5461
graphql-docs -h
5562
```
5663

64+
### Rack Application (Dynamic)
65+
66+
For more flexibility and control, you can serve documentation dynamically using the Rack application. This is useful for:
67+
68+
- Internal tools with frequently changing schemas
69+
- Integration with existing Rails/Sinatra applications
70+
- Adding authentication/authorization middleware
71+
- Dynamic schema loading from databases or APIs
72+
73+
**Requirements**: The Rack application feature requires the `rack` gem (version 2.x or 3.x). Add it to your Gemfile:
74+
75+
```ruby
76+
gem 'rack', '~> 3.0' # or '~> 2.0' for Rack 2.x
77+
```
78+
79+
The gem is compatible with both Rack 2.x and 3.x, so you can use whichever version your application requires.
80+
81+
#### Standalone Rack App
82+
83+
Create a `config.ru` file:
84+
85+
```ruby
86+
require 'graphql-docs'
87+
88+
schema = File.read('schema.graphql')
89+
90+
app = GraphQLDocs::App.new(
91+
schema: schema,
92+
options: {
93+
base_url: '',
94+
use_default_styles: true,
95+
cache: true # Enable page caching
96+
}
97+
)
98+
99+
run app
100+
```
101+
102+
Then run with:
103+
104+
```console
105+
rackup config.ru
106+
```
107+
108+
Visit `http://localhost:9292` to view your docs.
109+
110+
#### Mounting in Rails
111+
112+
```ruby
113+
# config/routes.rb
114+
require 'graphql-docs'
115+
116+
Rails.application.routes.draw do
117+
mount GraphQLDocs::App.new(schema: MyGraphQLSchema) => '/docs'
118+
end
119+
```
120+
121+
#### Mounting in Sinatra
122+
123+
```ruby
124+
require 'sinatra'
125+
require 'graphql-docs'
126+
127+
schema = File.read('schema.graphql')
128+
docs_app = GraphQLDocs::App.new(schema: schema)
129+
130+
map '/docs' do
131+
run docs_app
132+
end
133+
134+
map '/' do
135+
run Sinatra::Application
136+
end
137+
```
138+
139+
#### Rack App Features
140+
141+
- **On-demand generation** - Pages are generated when requested
142+
- **Built-in caching** - Generated pages are cached in memory (disable with `cache: false`)
143+
- **Schema reloading** - Update schema without restarting server:
144+
145+
```ruby
146+
app = GraphQLDocs::App.new(schema: schema)
147+
148+
# Later, reload with new schema
149+
new_schema = File.read('updated_schema.graphql')
150+
app.reload_schema!(new_schema)
151+
```
152+
153+
- **Asset serving** - CSS, fonts, and images served automatically
154+
- **Error handling** - Friendly error pages for missing types
155+
156+
#### SSG vs Rack Comparison
157+
158+
| Feature | SSG | Rack App |
159+
|---------|-----|----------|
160+
| Setup complexity | Low | Medium |
161+
| First page load | Instant | Fast (with caching) |
162+
| Schema updates | Manual rebuild | Automatic/reload |
163+
| Hosting | Any static host | Requires Ruby server |
164+
| Memory usage | Minimal | Higher (cached pages) |
165+
| Authentication | Separate layer | Built-in middleware |
166+
| Best for | Public docs, open source | Internal tools, dynamic schemas |
167+
57168
## Breakdown
58169

59170
There are several phases going on the single `GraphQLDocs.build` call:
@@ -395,20 +506,42 @@ an interactive prompt that will allow you to experiment.
395506

396507
## Sample Site
397508

398-
Clone this repository and run:
509+
Clone this repository and try out both modes:
399510

400-
```
511+
### Static Site Generation
512+
513+
Generate the sample documentation to the `output` directory:
514+
515+
```console
401516
bin/rake sample:generate
402517
```
403518

404-
to see some sample output in the `output` dir.
519+
Then boot up a server to view the pre-generated files:
520+
521+
```console
522+
bin/rake sample:serve
523+
```
524+
525+
Visit `http://localhost:5050` to view the static documentation.
405526

406-
Boot up a server to view it:
527+
### Rack Application (Dynamic)
407528

529+
Run the sample docs as a dynamic Rack application:
530+
531+
```console
532+
bin/rake sample:rack
408533
```
409-
bin/rake sample:serve
534+
535+
Or use the config.ru directly:
536+
537+
```console
538+
rackup config.ru
410539
```
411540

541+
Visit `http://localhost:9292` to view the documentation served dynamically.
542+
543+
**Key Difference**: The SSG version pre-generates all pages (faster initial load, no runtime cost), while the Rack version generates pages on-demand (better for dynamic schemas, easier integration).
544+
412545
## Credits
413546

414547
Originally built by [gjtorikian](https://github.com/gjtorikian). Actively maintained by [brettchalupa](https://github.com/brettchalupa).

Rakefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,34 @@ namespace :sample do
8383
server.start
8484
end
8585
task server: :serve
86+
87+
desc 'Run the sample docs as a Rack application (dynamic, on-demand generation)'
88+
task :rack do
89+
require 'rack'
90+
require 'graphql-docs'
91+
92+
schema_path = File.join(File.dirname(__FILE__), 'test', 'graphql-docs', 'fixtures', 'gh-schema.graphql')
93+
schema = File.read(schema_path)
94+
95+
app = GraphQLDocs::App.new(
96+
schema: schema,
97+
options: {
98+
base_url: '',
99+
use_default_styles: true,
100+
cache: true
101+
}
102+
)
103+
104+
PORT = ENV.fetch('PORT', '9292')
105+
puts "Starting Rack server in dynamic mode (on-demand generation)"
106+
puts "Navigate to http://localhost:#{PORT} to view the sample docs"
107+
puts "Press Ctrl+C to stop"
108+
puts ""
109+
puts "NOTE: This serves documentation dynamically - pages are generated on request"
110+
puts " Compare with 'rake sample:serve' which serves pre-generated static files"
111+
puts ""
112+
113+
# Use rackup for Rack 3.x compatibility
114+
sh "rackup config.ru -p #{PORT}"
115+
end
86116
end

config.ru

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# frozen_string_literal: true
2+
3+
# Rack configuration file for running GraphQL Docs as a web server
4+
#
5+
# This demonstrates using GraphQLDocs as a Rack application that serves
6+
# documentation dynamically on-demand instead of pre-generating static files.
7+
#
8+
# Run with: rackup config.ru
9+
# Or with specific port: rackup config.ru -p 9292
10+
11+
require_relative 'lib/graphql-docs'
12+
13+
# Load the sample GraphQL schema
14+
schema_path = File.join(__dir__, 'test', 'graphql-docs', 'fixtures', 'gh-schema.graphql')
15+
16+
unless File.exist?(schema_path)
17+
puts "Error: Sample schema not found at #{schema_path}"
18+
puts "Please ensure the schema file exists before starting the server."
19+
exit 1
20+
end
21+
22+
schema = File.read(schema_path)
23+
24+
# Create the Rack app
25+
app = GraphQLDocs::App.new(
26+
schema: schema,
27+
options: {
28+
base_url: '',
29+
use_default_styles: true,
30+
cache: true
31+
}
32+
)
33+
34+
# Log requests in development
35+
use Rack::CommonLogger
36+
37+
# Add reloader for development (optional, requires 'rack' gem)
38+
if ENV['RACK_ENV'] != 'production'
39+
puts "Running in development mode"
40+
puts "Visit http://localhost:9292 to view the documentation"
41+
puts "Press Ctrl+C to stop the server"
42+
end
43+
44+
run app

graphql-docs.gemspec

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,17 @@ Gem::Specification.new do |spec|
4949
spec.add_dependency 'ostruct', '~> 0.6'
5050
spec.add_dependency 'logger', '~> 1.6'
5151

52+
# rack application support (optional, only needed for GraphQLDocs::App)
53+
# Users can install rack separately if they want to use the Rack app feature:
54+
# gem 'rack', '~> 2.0' or gem 'rack', '~> 3.0'
55+
# The gem works with both Rack 2.x and 3.x
56+
5257
spec.add_development_dependency 'html-proofer', '~> 3.4'
5358
spec.add_development_dependency 'minitest', '~> 5.24'
5459
spec.add_development_dependency 'minitest-focus', '~> 1.1'
60+
spec.add_development_dependency 'rack', '>= 2.0', '< 4'
61+
spec.add_development_dependency 'rack-test', '~> 2.0'
62+
spec.add_development_dependency 'rackup', '~> 2.0'
5563
spec.add_development_dependency 'rake', '~> 13.0'
5664
spec.add_development_dependency 'rubocop', '~> 1.37'
5765
spec.add_development_dependency 'rubocop-performance', '~> 1.15'

lib/graphql-docs.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
require 'graphql-docs/parser'
88
require 'graphql-docs/version'
99

10+
# Lazy-load the Rack app - only loads if Rack is available
11+
begin
12+
require 'graphql-docs/app' if defined?(Rack)
13+
rescue LoadError
14+
# Rack not available, App class won't be loaded
15+
end
16+
1017
# GraphQLDocs is a library for generating beautiful HTML documentation from GraphQL schemas.
1118
# It parses GraphQL schema files or schema objects and generates a complete documentation website
1219
# with customizable templates and styling.

0 commit comments

Comments
 (0)