Skip to content
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

Obtain response on ajax() call, even if there's a 404 #2059

Closed
rgbkrk opened this issue Oct 22, 2016 · 10 comments
Closed

Obtain response on ajax() call, even if there's a 404 #2059

rgbkrk opened this issue Oct 22, 2016 · 10 comments

Comments

@rgbkrk
Copy link
Contributor

rgbkrk commented Oct 22, 2016

RxJS version:

5.0.0-rc.1

Code to reproduce:

import { Observable } from 'rxjs';
import { ajax } from 'rxjs/observable/dom/ajax';

const asdf = ajax("https://api.github.com/asdf")
               .catch(err => err.xhr ? Observable.of(err) : Observable.of('.___.'))

asdf.subscribe(x => console.log(x)); 

Expected behavior:

On a 404, I expect to be able to get the payload/response. With the "API" I used above, I'd want to have:

{
  "message": "Not Found",
  "documentation_url": "https://developer.github.com/v3"
}

With fetch I get the response.

Actual behavior:

Result, that can be .caught, is an AjaxError and has rough structure (note no response):

{
  "message": "ajax error 404",
  "xhr": {},
  "request": {
    "async": true,
    "crossDomain": false,
    "withCredentials": false,
    "headers": {
      "X-Requested-With": "XMLHttpRequest"
    },
    "method": "GET",
    "responseType": "json",
    "timeout": 0,
    "url": "https://api.github.com/asdf"
  },
  "status": 404
}

I want the response body. Is there any way to surface it?

@jayphelps
Copy link
Member

jayphelps commented Oct 22, 2016

@rgbkrk seems to work for me? http://jsbin.com/duwuwi/edit?js,console

image

Perhaps I'm confused?

Is there something subtly different in your project that's not the same as the provided example? For example, the browser won't automatically parse the response JSON if the server didn't say the response Content-Type was "application/json" (this trips people up sometimes). You can set responseType: 'json' tho to tell it to parse it regardless or you can JSON.parse(error.xhr.responseText). Though your demo suggests the xhr object was actually empty entirely?? That's really really really odd if true.

@rgbkrk
Copy link
Contributor Author

rgbkrk commented Oct 22, 2016

Though your demo suggests the xhr object was actually empty entirely?? That's really really really odd if true.

Well, I did run a JSON.stringify on the AjaxError in order to dump it here in the issue.

@rgbkrk plays with the jsbin for a bit based on your example

Now I see. In order to make 4xx and 5xx responses have the same format as responses with a 2xx status code, I have to pluck the .xhr:

  .catch(err => Observable.of(err.xhr))

@rgbkrk
Copy link
Contributor Author

rgbkrk commented Oct 22, 2016

Now that I see how to use this, it makes me wish I posted this as a StackOverflow issue instead. 😉

For the sake of me helping others in open source, around the web, and on my team - what's the reasoning behind making 404s and others turn into errors?

@jayphelps
Copy link
Member

@rgbkrk ohhh I think I see, you're talking about the fact that error vs non-error objects differ

// error
{
  message: "ajax error 404",
  status: 404,
  xhr: { ... },
  request: { ... }
}

// success
{
  status: 200,
  xhr: { ... },
  request: { ... },
  response: { ... },
  responseType: "json",
  originalEvent: { ... }
}

It's not immediately clear if this is intentional or if just an oversight. I can't see any problem with having the response stuff on the top-level error object.

@jayphelps
Copy link
Member

@rgbkrk

what's the reasoning behind making 404s and others turn into errors?

Do you mean why is it an exception you have to catch or why is does the exception not have the response at the top level like the success object does?

@rgbkrk
Copy link
Contributor Author

rgbkrk commented Oct 22, 2016

Do you mean why is it an exception you have to catch

Yes.

@rgbkrk
Copy link
Contributor Author

rgbkrk commented Oct 22, 2016

It's not immediately clear if this is intentional or if just an oversight. I can't see any problem with having the response stuff on the top-level error object.

If the response was in the top-level object I certainly wouldn't have gone to the documentation or issues, I would have just passed it on with a catch - it would be apparent to me as a user how to work with it.

@jayphelps
Copy link
Member

jayphelps commented Oct 22, 2016

Do you mean why is it an exception you have to catch

Yes.

I don't have true backstory on why, but I can make several guesses: v4 did it that way and no one has likely challenged it recently AFAICT. Also that this is common for ajax utils, e.g. jQuery.ajax does this with the promise returned, taking you down the reject path.

That said, the window.fetch() API does not go down the reject path for non-200's which some have actually complained about

A fetch() promise will reject with a TypeError when a network error is encountered, although this usually means permission issues or similar — a 404 does not constitute a network error, for example.

I think which one a person prefers really depends on the person and the use case. Most of the time a non-200 really is exceptional and I personally prefer the exception path for these because then my "happy path" isn't cluttered with error checks and also if I don't have some way to recover from the error I can not catch it, letting it propagate and catch in a single place to log (or the console) instead of it going down the happy path, causing a reference error and losing what would have been on the error object--so then errors logged are ambiguous.

This is probably all debatable though. We might, for instance, default to similar to behavior as fetch() and accept a config to say what is and isn't happy like ajax(url, { successCode: '2xx' }).

@rgbkrk
Copy link
Contributor Author

rgbkrk commented Oct 22, 2016

That makes perfect sense. In terms of ideal Rx flows, next and error stay very true to purpose. This informs me as to what our API in rx-jupyter should do with errors: nothing. We'll let folks handle them as they want to, documenting the way in which the errors work (which we'll happily defer to RxJS docs when we can). /cc @jdetle @captainsafia

@rgbkrk rgbkrk closed this as completed Oct 22, 2016
@lock
Copy link

lock bot commented Jun 6, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 6, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants