Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Allow rescuing an API 404 #177

Closed
amrnt opened this Issue · 14 comments

3 participants

Amr Tamimi Daniel Doubrovkine (dB.) @dblockdotorg Xavier Cambar
Amr Tamimi

When you access an url that's not defined in the API, you get a 404 default plain text. There should be a way to override it.

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

This is just the default handler for the error in .txt format. You can get JSON format, text format or rescue explicitly. Read "Exception Handling" in the README.

Please do use the google group for further questions.

Daniel Doubrovkine (dB.) @dblockdotorg dblock closed this
Amr Tamimi

Okay. Let me state the issue better;

I've already use rescue_from, like so

  error_format :json
  rescue_from :all, backtrace: true
  rescue_from ActiveRecord::RecordNotFound do |e|
    rack_response('{ "status": 404, "message": "Not Found." }', 404)
  end

What my question was about is; When I call a URL that is not defined in the app I got Not Found Error as plain text.

I dont know if It's Grape or Rack case!

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

The first parameter in rack_response should be a hash, not a string?

rack_response({ "status": 404, "message": "Not Found." }, 404)
Amr Tamimi

rack_response first param is a string. When I do what you said I doesn't render a valid JSON. This is the response:

{"status"=>404, "message"=>"Not Found."}

https://github.com/intridea/grape/blob/master/lib/grape/middleware/error.rb#L68

@dblock I'm not talking about this. This issue is when I access an invalid URL in my api application I got a 404 error rendered 'Not Found' with plain/text type (Grape content type default).

For example, in an api I have GET /me/filters when I have a typo like GET /me/filterrsy I got Error 404 as I said before.

Daniel Doubrovkine (dB.) @dblockdotorg dblock reopened this
Daniel Doubrovkine (dB.) @dblockdotorg
Owner

Ok. I think I understand now. Grape will return the default 404 in case the API doesn't exist and there's no handler for that that you can override. I reopened this as a feature request. In the meantime, check out my demo app. I added a way to handle the API 404 in a middleware in this commit. Depending on how you setup your app you can do the same or you can just put a middleware in front of grape that looks at the Rack's response[0] and does something else when it's a 404 (eg. serve a static file via Rack::Static like in my demo).

Does this help?

Amr Tamimi

Thank you very much for opening it again, and for ur solution...

Amr Tamimi

I'm not sure if this could solve the problem, to put this piece of code at the very bottom of the api application:

get '/(*:url)', :anchor => false do
  # raise 404 with json response
end

See these cases for more info:

API_SERVER/1/ --> Entity not found: /1
API_SERVER/1/links --> Not defined in the api as endpoint for /links --> Entity not found: /1/links
API_SERVER/2/links/search --> defined in the api --> returns json data as expected
API_SERVER/2/links --> Not defined in the api as endpoint for /links --> returns the response above of 404
API_SERVER/2/linkss --> Not defined in the api --> returns the response above of 404
API_SERVER/2/ --> Entity not found: /2

For my code I almost organize it as u describe here: http://code.dblock.org/modularizing-a-ror-grape-api-multiple-versions

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

I tried to implement something for this today and I am not sure what we want. There's no exception raised, this is just Rack not finding a route. So the call to call in api.rb returns [404, {"Content-Type"=>"text/html", "X-Cascade"=>"pass"}, ["Not Found"]]. We could do something where you can process every single response here, for example:

rescue_from :404 do 
 ...
end

or to be less ambiguous

on_response :404 do
 ...
end

But this is also nicely solved by inserting a middleware after grape that does the same logic.

Open to suggestions.

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

The catch-all path should look like this:

route :any, '*path' do
  error! # or something else
end

Here's a catch-all implementation with spec.

Amr Tamimi

Awesome :+1:

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

I also think specifying cascade: false may be another solution. This would tell Rails not to process further. Can you try this? Can I close this?

Amr Tamimi

Actually I'm not using Rails... but I confirm its working as expected!

Amr Tamimi amrnt closed this
Xavier Cambar

Maybe the catch-all example should go into the README for more visibility.

Daniel Doubrovkine (dB.) @dblockdotorg
Owner

@xcambar feel free to PR

Xavier Cambar xcambar referenced this issue from a commit in xcambar/grape
Xavier Cambar xcambar refs #177 Adds a catch-all example in the README b22754e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.