Repository navigation
Rails api #19832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rails api #19832
Changes from all commits
032778e
2d86b6d
135c059
212a099
3adb5ea
2a9cf48
c09a401
e8915d0
1718683
9b66071
3847e48
7b47e42
101df20
c190352
e8100fc
20939b3
d4fe23c
451b1e3
6d2b405
e5b6188
94fdba9
decc4e8
98a9936
e9e94c1
7d17269
3d37300
4c1b437
4204778
38818c9
e7b89f1
b643d7a
440b334
099055d
674dab3
e380887
fd25085
fa11f10
2487bfb
08cfe34
11c71b2
7db63f3
b6c270f
846f352
dc4c68a
511c33a
03b576e
37507d3
b7494b6
f3df216
564d029
80702b7
72d0784
ebcc15c
a2c9a73
cf9f2f3
afc78e7
8d3e6e5
6c16577
1fd42f3
51d5d62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| require 'action_view' | ||
| require 'action_controller' | ||
| require 'action_controller/log_subscriber' | ||
|
|
||
| module ActionController | ||
| # API Controller is a lightweight version of <tt>ActionController::Base</tt>, | ||
| # created for applications that don't require all functionality that a complete | ||
| # \Rails controller provides, allowing you to create controllers with just the | ||
| # features that you need for API only applications. | ||
| # | ||
| # An API Controller is different from a normal controller in the sense that | ||
| # by default it doesn't include a number of features that are usually required | ||
| # by browser access only: layouts and templates rendering, cookies, sessions, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still do allow template rendering for jbuilder I suppose?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, this module is added back from jbuilder itself rails/jbuilder@29c0014#diff-524d52316875e7ab48f1778a8ae620cfR14 |
||
| # flash, assets, and so on. This makes the entire controller stack thinner, | ||
| # suitable for API applications. It doesn't mean you won't have such | ||
| # features if you need them: they're all available for you to include in | ||
| # your application, they're just not part of the default API Controller stack. | ||
| # | ||
| # By default, only the ApplicationController in a \Rails application inherits | ||
| # from <tt>ActionController::API</tt>. All other controllers in turn inherit | ||
| # from ApplicationController. | ||
| # | ||
| # A sample controller could look like this: | ||
| # | ||
| # class PostsController < ApplicationController | ||
| # def index | ||
| # @posts = Post.all | ||
| # render json: @posts | ||
| # end | ||
| # end | ||
| # | ||
| # Request, response and parameters objects all work the exact same way as | ||
| # <tt>ActionController::Base</tt>. | ||
| # | ||
| # == Renders | ||
| # | ||
| # The default API Controller stack includes all renderers, which means you | ||
| # can use <tt>render :json</tt> and brothers freely in your controllers. Keep | ||
| # in mind that templates are not going to be rendered, so you need to ensure | ||
| # your controller is calling either <tt>render</tt> or <tt>redirect</tt> in | ||
| # all actions, otherwise it will return 204 No Content response. | ||
| # | ||
| # def show | ||
| # @post = Post.find(params[:id]) | ||
| # render json: @post | ||
| # end | ||
| # | ||
| # == Redirects | ||
| # | ||
| # Redirects are used to move from one action to another. You can use the | ||
| # <tt>redirect</tt> method in your controllers in the same way as | ||
| # <tt>ActionController::Base</tt>. For example: | ||
| # | ||
| # def create | ||
| # redirect_to root_url and return if not_authorized? | ||
| # # do stuff here | ||
| # end | ||
| # | ||
| # == Adding new behavior | ||
| # | ||
| # In some scenarios you may want to add back some functionality provided by | ||
| # <tt>ActionController::Base</tt> that is not present by default in | ||
| # <tt>ActionController::API</tt>, for instance <tt>MimeResponds</tt>. This | ||
| # module gives you the <tt>respond_to</tt> and <tt>respond_with</tt> methods. | ||
| # Adding it is quite simple, you just need to include the module in a specific | ||
| # controller or in <tt>ApplicationController</tt> in case you want it | ||
| # available to your entire app: | ||
| # | ||
| # class ApplicationController < ActionController::API | ||
| # include ActionController::MimeResponds | ||
| # end | ||
| # | ||
| # class PostsController < ApplicationController | ||
| # def index | ||
| # @posts = Post.all | ||
| # | ||
| # respond_to do |format| | ||
| # format.json { render json: @posts } | ||
| # format.xml { render xml: @posts } | ||
| # end | ||
| # end | ||
| # end | ||
| # | ||
| # Quite straightforward. Make sure to check <tt>ActionController::Base</tt> | ||
| # available modules if you want to include any other functionality that is | ||
| # not provided by <tt>ActionController::API</tt> out of the box. | ||
| class API < Metal | ||
| abstract! | ||
|
|
||
| # Shortcut helper that returns all the ActionController::API modules except the ones passed in the argument: | ||
| # | ||
| # class MetalController | ||
| # ActionController::API.without_modules(:Redirecting, :DataStreaming).each do |left| | ||
| # include left | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why leaving the include for the users since it is only what they can do? I think we should implement it for ourself and just require users to do: ActionController::API.without_modules(:Redirecting, :DataStreaming)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feature already exists in Base so I wouldn't change the current API
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π |
||
| # end | ||
| # end | ||
| # | ||
| # This gives better control over what you want to exclude and makes it easier | ||
| # to create an api controller class, instead of listing the modules required manually. | ||
| def self.without_modules(*modules) | ||
| modules = modules.map do |m| | ||
| m.is_a?(Symbol) ? ActionController.const_get(m) : m | ||
| end | ||
|
|
||
| MODULES - modules | ||
| end | ||
|
|
||
| MODULES = [ | ||
| AbstractController::Rendering, | ||
|
|
||
| UrlFor, | ||
| Redirecting, | ||
| Rendering, | ||
| Renderers::All, | ||
| ConditionalGet, | ||
| RackDelegation, | ||
| BasicImplicitRender, | ||
| StrongParameters, | ||
|
|
||
| ForceSSL, | ||
| DataStreaming, | ||
|
|
||
| # Before callbacks should also be executed the earliest as possible, so | ||
| # also include them at the bottom. | ||
| AbstractController::Callbacks, | ||
|
|
||
| # Append rescue at the bottom to wrap as much as possible. | ||
| Rescue, | ||
|
|
||
| # Add instrumentations hooks at the bottom, to ensure they instrument | ||
| # all the methods properly. | ||
| Instrumentation, | ||
|
|
||
| # Params wrapper should come before instrumentation so they are | ||
| # properly showed in logs | ||
| ParamsWrapper | ||
| ] | ||
|
|
||
| MODULES.each do |mod| | ||
| include mod | ||
| end | ||
|
|
||
| ActiveSupport.run_load_hooks(:action_controller, self) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| module ActionController | ||
| module BasicImplicitRender | ||
| def send_action(method, *args) | ||
| super.tap { default_render unless performed? } | ||
| end | ||
|
|
||
| def default_render(*args) | ||
| head :no_content | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| require 'abstract_unit' | ||
| require 'active_support/core_ext/integer/time' | ||
| require 'active_support/core_ext/numeric/time' | ||
|
|
||
| class ConditionalGetApiController < ActionController::API | ||
| before_action :handle_last_modified_and_etags, only: :two | ||
|
|
||
| def one | ||
| if stale?(last_modified: Time.now.utc.beginning_of_day, etag: [:foo, 123]) | ||
| render text: "Hi!" | ||
| end | ||
| end | ||
|
|
||
| def two | ||
| render text: "Hi!" | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def handle_last_modified_and_etags | ||
| fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ]) | ||
| end | ||
| end | ||
|
|
||
| class ConditionalGetApiTest < ActionController::TestCase | ||
| tests ConditionalGetApiController | ||
|
|
||
| def setup | ||
| @last_modified = Time.now.utc.beginning_of_day.httpdate | ||
| end | ||
|
|
||
| def test_request_gets_last_modified | ||
| get :two | ||
| assert_equal @last_modified, @response.headers['Last-Modified'] | ||
| assert_response :success | ||
| end | ||
|
|
||
| def test_request_obeys_last_modified | ||
| @request.if_modified_since = @last_modified | ||
| get :two | ||
| assert_response :not_modified | ||
| end | ||
|
|
||
| def test_last_modified_works_with_less_than_too | ||
| @request.if_modified_since = 5.years.ago.httpdate | ||
| get :two | ||
| assert_response :success | ||
| end | ||
|
|
||
| def test_request_not_modified | ||
| @request.if_modified_since = @last_modified | ||
| get :one | ||
| assert_equal 304, @response.status.to_i | ||
| assert @response.body.blank? | ||
| assert_equal @last_modified, @response.headers['Last-Modified'] | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove Compatability?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of that line is unrelated, but anyway it's a module that does not exist anymore.