Skip to content

Commit 3ad8b7a

Browse files
committed
Add a bunch of documentation
1 parent 7761d3c commit 3ad8b7a

File tree

17 files changed

+223
-64
lines changed

17 files changed

+223
-64
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
.bundle/
2+
.yardoc/
3+
doc/
24
log/*.log
35
pkg/
46
spec/.rspec-examples.txt

.yardext.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'kramdown'
2+
require 'yard'
3+
4+
# Make new Kramdown class with Github Formatted Markdown on
5+
class KramdownGFM < Kramdown::Document
6+
def initialize(text, opts={})
7+
super(text, opts.merge(input: 'GFM', hard_wrap: false))
8+
end
9+
end
10+
11+
# Register new KramdownGFM
12+
YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown] <<
13+
{ lib: :"kramdown-parser-gfm", :const => "KramdownGFM" }
14+
15+
# Register custom templates
16+
YARD::Templates::Engine.register_template_path File.expand_path("yard/templates", __dir__)
17+

.yardopts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--no-private
2+
--load .yardext.rb
3+
--markup-provider=kramdown-parser-gfm
4+
--markup=markdown

Gemfile.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ GEM
116116
activerecord
117117
kaminari-core (= 1.1.1)
118118
kaminari-core (1.1.1)
119+
kramdown (2.1.0)
120+
kramdown-parser-gfm (1.0.1)
121+
kramdown (~> 2.0)
119122
loofah (2.2.3)
120123
crass (~> 1.0.2)
121124
nokogiri (>= 1.5.9)
@@ -168,6 +171,7 @@ GEM
168171
responders (2.4.0)
169172
actionpack (>= 4.2.0, < 5.3)
170173
railties (>= 4.2.0, < 5.3)
174+
rouge (3.3.0)
171175
rspec (3.8.0)
172176
rspec-core (~> 3.8.0)
173177
rspec-expectations (~> 3.8.0)
@@ -204,6 +208,7 @@ GEM
204208
websocket-driver (0.7.0)
205209
websocket-extensions (>= 0.1.0)
206210
websocket-extensions (0.1.3)
211+
yard (0.9.19)
207212

208213
PLATFORMS
209214
ruby
@@ -214,11 +219,14 @@ DEPENDENCIES
214219
graphiti-rails!
215220
graphiti_spec_helpers (~> 1.0.1)
216221
kaminari
222+
kramdown-parser-gfm
217223
pry
218224
pry-byebug
219225
responders
226+
rouge
220227
rspec-rails
221228
sqlite3
229+
yard
222230

223231
BUNDLED WITH
224232
2.0.1

README.md

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Graphiti::Rails
22

3-
Graphiti::Rails is a more robust Rails integration for Graphiti.
3+
Graphiti::Rails provides robust Rails integration for Graphiti, following standard Rails conventions.
44

55
## Usage
6-
TODO
6+
Out of the box, Graphiti::Rails requires no configuration!
77

88
## Installation
99
Add this line to your application's Gemfile:
@@ -13,42 +13,49 @@ gem 'graphiti-rails'
1313
```
1414

1515
### Additional Setup
16-
We also recommend that you set `config.debug_exception_response_format = :api` in your `config/application.rb`.
17-
This will cause the [`ActionDispatch::DebugExceptions`][debug-exceptions]
18-
middleware to generate debug information in the requested content-type instead of as HTML only. In turn, this allows
19-
graphti-rails to generate more specific error messages for JSON API requests.
16+
We also recommend the following in `config/application.rb`:
17+
18+
```ruby
19+
config.debug_exception_response_format = :api
20+
```
21+
22+
This will cause the [`ActionDispatch::DebugExceptions`][debug-exceptions] middleware to generate debug information in the requested content-type instead of as HTML only. In turn, this allows graphti-rails to generate more specific error messages for JSON API requests.
2023

2124
## Features
2225

2326
### Exception Handling
24-
By default, Rails does a few things to handle exceptions. We integrate into this handling to ensure behavior
25-
as close to the Rails defaults while still adding important conventions and additional information provide by
26-
Graphiti.
27+
By default, Rails does a few things to handle exceptions. We integrate into this handling to ensure behavior as close to the Rails defaults while still adding important conventions and additional information provide by Graphiti.
2728

2829
#### `rescue_from`
2930

30-
At the highest level, is [`rescue_from`][rescue-from] which allows you to handle an error at the controller level.
31-
This bypasses all default error handling in Rails, leaving it up to the developer to account for all scenarios.
32-
In the future, we would like to provide some APIs for default handling in these cases.
31+
At the highest level, is [`rescue_from`][rescue-from] which allows you to handle an error at the controller level. This bypasses all default error handling in Rails, leaving it up to the developer to account for all scenarios. In the future, we would like to provide some APIs for default handling in these cases.
3332

3433
#### `ActionDispatch::DebugExceptions`
3534

36-
Next is [`ActionDispatch::DebugExceptions`][debug-exceptions]. This middleware logs exceptions and renders debugging
37-
information for local requests. We hook in here to log more information available from some Graphiti exceptions.
35+
Next is [`ActionDispatch::DebugExceptions`][debug-exceptions]. This middleware logs exceptions and renders debugging information for local requests. We hook in here to log information in a proper format for JSON:API.
3836

3937
#### `ActionDispatch::ShowExceptions`
4038

41-
Last is [`ActionDispatch::ShowExceptions`][show-exceptions]. This middleware rescues any exception returned by the
42-
application and calls an exceptions app that will wrap it in a format for the end user. We wrap the exceptions app
43-
to ensure that JSON API errors are always rendered in the standard format.
39+
Last is [`ActionDispatch::ShowExceptions`][show-exceptions]. This middleware rescues any exception returned by the application and calls an exceptions app that will wrap it in a format for the end user. We wrap the exceptions app to ensure that JSON:API errors are always rendered in the standard format.
40+
41+
### Context Wrapping
42+
We wrap all requests in a Graphiti context pointing to the current controller instance. If you'd like to use a different context, overwrite the `graphiti_context` method in your controller.
43+
44+
For more information about Graphiti context, see the [Graphiti docs][context].
45+
46+
### Debugging
47+
We also provide hooks for Graphiti's built-in debugger. For more information see the [Graphiti docs][debugger].
4448

4549
## Contributing
46-
Contribution directions go here.
50+
We'd love to have your help improving graphiti-rails. To chat with the team and other users, join the `#rails` channel on [Slack][slack].
4751

4852
## License
4953
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
5054

5155

5256
[debug-exceptions]: https://api.rubyonrails.org/classes/ActionDispatch/DebugExceptions.html
53-
[rescue-from]: (https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from)
57+
[context]: https://www.graphiti.dev/guides/concepts/resources#context
58+
[debugger]: https://www.graphiti.dev/guides/concepts/debugging#debugger
59+
[rescue-from]: https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from
5460
[show-exceptions]: https://api.rubyonrails.org/classes/ActionDispatch/ShowExceptions.html
61+
[slack]: https://join.slack.com/t/graphiti-api/shared_invite/enQtMjkyMTA3MDgxNTQzLWVkMDM3NTlmNTIwODY2YWFkMGNiNzUzZGMzOTY3YmNmZjBhYzIyZWZlZTk4YmI1YTI0Y2M0OTZmZGYwN2QxZjg

Rakefile

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,11 @@ rescue LoadError
44
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
55
end
66

7-
require 'rdoc/task'
7+
require 'yard'
88
require 'rspec/core/rake_task'
99
require 'bundler/gem_tasks'
1010

11-
RDoc::Task.new(:rdoc) do |rdoc|
12-
rdoc.rdoc_dir = 'rdoc'
13-
rdoc.title = 'Graphiti::Rails'
14-
rdoc.options << '--line-numbers'
15-
rdoc.rdoc_files.include('README.md')
16-
rdoc.rdoc_files.include('lib/**/*.rb')
17-
end
11+
YARD::Rake::YardocTask.new
1812

1913
RSpec::Core::RakeTask.new(:spec) do |t|
2014
t.rspec_opts = "--order random"

graphiti-rails.gemspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@ Gem::Specification.new do |spec|
3434
spec.add_development_dependency "kaminari"
3535
spec.add_development_dependency "factory_bot"
3636
spec.add_development_dependency "responders"
37+
spec.add_development_dependency "yard"
38+
spec.add_development_dependency "kramdown-parser-gfm"
39+
spec.add_development_dependency "rouge"
3740
end

lib/graphiti/rails.rb

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Graphiti
55
remove_const :Rails
66
end
77

8+
# Rails integration for Graphiti. See {file:README.md} for more details.
89
module Rails
910
# While this allow custom errors to be registered we currently don't recommend relying on this
1011
# functionality unless you are absolutely certain you know what you're doing. The main issue is
@@ -15,6 +16,8 @@ def self.included(_klass)
1516
ActiveSupport::Deprecation.warn("With graphiti-rails, including Graphiti::Rails is unnecessary")
1617
end
1718

19+
# A list of formats as symbols which will be handled by a GraphitiErrors::ExceptionHandler.
20+
# Defaults to `[:jsonapi]`.
1821
cattr_accessor :handled_exception_formats, default: []
1922

2023
autoload :Context, "graphiti/rails/context"
@@ -23,6 +26,9 @@ def self.included(_klass)
2326
autoload :DefaultExceptionHandler, "graphiti/rails/exception_handlers"
2427
autoload :InvalidRequestExceptionHandler, "graphiti/rails/exception_handlers"
2528

29+
# The default exception handler for Graphiti::Rails errors.
30+
# In general, you should not need to call or modify this.
31+
# @private
2632
def self.default_exception_handler
2733
DefaultExceptionHandler
2834
end
@@ -32,24 +38,36 @@ def self.default_exception_handler
3238
handler: InvalidRequestExceptionHandler
3339
end
3440

41+
# Returns a boolean of whether the specified content type should be handled by a Graphiti exception handler.
42+
# The list of format can be found in `.handled_exception_formats`.
43+
# @param content_type [Mime::Type]
44+
# @return [Boolean]
3545
def self.render_exception_for_format?(content_type)
3646
handled_exception_formats.include?(content_type.to_sym)
3747
end
3848

39-
# TODO: Move this into GraphitiErrors
49+
# @return [GraphitiErrors::ExceptionHandler]
4050
def self.exception_handler_for(exception)
51+
# TODO: Move this into GraphitiErrors
4152
_errorable_registry[exception.class] || default_exception_handler.new
4253
end
4354

44-
# TODO: Move this into GraphitiErrors
55+
# @param [Exception] exception
56+
# @param [Boolean] show_raw_error (false)
57+
# @return [Array<Integer, Hash>] HTTP status and payload
4558
def self.exception_details(exception, show_raw_error: false)
59+
# TODO: Move this into GraphitiErrors
4660
exception_klass = exception_handler_for(exception)
4761
exception_klass.show_raw_error = show_raw_error
4862
status = exception_klass.status_code(exception)
4963
payload = exception_klass.error_payload(exception)
5064
[status, payload]
5165
end
5266

67+
# @param [Exception] exception
68+
# @param [Mime::Type] content_type
69+
# @param [Hash] keywords passed through to {.exception_details}
70+
# @return [Array<Integer, Mime::Type, String>] HTTP status, content type, and payload
5371
def self.rendered_exception(exception, content_type:, **keywords)
5472
status, body = exception_details(exception, **keywords)
5573

lib/graphiti/rails/action_dispatch.rb

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,30 @@
11
# The standard Rails ShowExceptions middleware passes exceptions on to `config.exceptions_app`.
2-
# However, the default exceptions_app (PublicExceptions) doesn't handle JSON API responses
3-
# correctly, so we wrap it ourselves to ensure correct handling.
4-
#
5-
# One potential problem here is if people want to handle the JSON API responses themselves.
6-
# In that case, we might actually want to extend PublicExceptions insteand and then let people use
7-
# their own handling when they overwite the exceptions app. The downside to this is that people
8-
# setting their own exceptions app may not know that they should handle JSON API specially.
9-
#
10-
# If we continue with this approach, we should see about getting an API into Rails for this.
11-
ActionDispatch::ShowExceptions.class_eval do
2+
# Here we wrap the specified exceptions app to handle desired content types via GraphititErrors::ExceptionHandler.
3+
# See {file:README.md#actiondispatchshowexceptions} for more details.
4+
class ActionDispatch::ShowExceptions
5+
# TODO: See about adding a Rails API for this
6+
7+
# @private
128
alias_method :initialize_without_graphiti, :initialize
9+
10+
# @private
1311
def initialize(*args)
1412
initialize_without_graphiti(*args)
1513
@exceptions_app = Graphiti::Rails::ExceptionsApp.new(@exceptions_app)
1614
end
1715
end
1816

19-
# Since we have more information for JSON API errors from Graphiti we hijack the defaults
20-
# and do do the better rendering. Ideally, we'd have a hook in Rails for this.
17+
# Here we monkeypatch to support using GraphitiErrors::ExceptionHandler where desired.
18+
# See {file:README.md#actiondispatchdebugexceptions} for more details.
2119
#
2220
# Set `config.debug_exception_response_format = :api` for this to work correctly.
2321
#
24-
# TODO: Investigate whether dev tools will render a returned HTML formatted error correctly.
25-
# If so, there may be some benefit in not changing `debug_exception_response_format` since
26-
# an HTML formatted error might be nicer to read than JSON formatted. However, we should
27-
# still handle the JSON API case correctly when `debug_exception_response_format == :api`.
28-
ActionDispatch::DebugExceptions.class_eval do
22+
# NOTE: There may be some benefit in not changing `debug_exception_response_format` since
23+
# an HTML formatted error might render more nicely in browser developer tools than JSON formatted.
24+
class ActionDispatch::DebugExceptions
2925
private
3026

27+
# TODO: Investigate adding a Rails hook for this.
3128
alias_method :render_for_api_request_without_graphiti, :render_for_api_request
3229
def render_for_api_request(content_type, wrapper)
3330
if Graphiti::Rails.render_exception_for_format?(content_type)

lib/graphiti/rails/context.rb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
module Graphiti
22
module Rails
3+
# Wraps controller actions in a [Graphiti Context](https://www.graphiti.dev/guides/concepts/resources#context) which points to the
4+
# controller instance by default.
35
module Context
46
def self.included(klass)
57
klass.class_eval do
6-
# QUESTION: Any downside to including this in all Rails controllers?
78
include Graphiti::Context
89
around_action :wrap_graphiti_context
910
end
1011
end
1112

12-
# QUESTION: Is it fine if we wrap even non-Graphiti actions?
13+
# Called by [`#around_action`](https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-around_action)
14+
# to wrap the current action in a Graphiti context defined by {#graphiti_context}.
1315
def wrap_graphiti_context
14-
Graphiti.with_context(jsonapi_context, action_name.to_sym) do
16+
Graphiti.with_context(graphiti_context, action_name.to_sym) do
1517
yield
1618
end
1719
end
1820

21+
# The context to use for Graphiti Resources. Defaults to the controller instance.
22+
# Can be redefined for different behavior.
23+
def graphiti_context
24+
jsonapi_context
25+
end
26+
27+
# @private
28+
# @deprecated Use {#graphiti_context} instead
1929
def jsonapi_context
2030
self
2131
end

0 commit comments

Comments
 (0)