elbywan / wretch

A tiny wrapper built around fetch with an intuitive syntax. :candy:
MIT License
4.79k stars 96 forks source link

Catcher not receiving error #87

Closed alexdemers closed 4 years ago

alexdemers commented 4 years ago

I defined a middleware to insert a XSRF token, which works and and a catcher when the server returns a 422 status. The catcher never receives the response.

const xsrfMiddleware = (next: FetchLike) => (url: string, opts: { [key: string]: any }) => {
    const csrfToken = cookie.get('XSRF-TOKEN');
    if (csrfToken !== undefined) {
        opts.headers = { ...opts.headers, 'X-XSRF-TOKEN': csrfToken };
    }
    return next(url, opts);
};

const accountPasswordCatcher = async (error: WretcherError) => {
    const response = await error.json();
    if ('account_password' in response.errors) {
        console.log('test');
    }
};

const Client = wrench()
    .options({ credentials: 'include', withCredentials: true })
    .polyfills({ fetch: window.fetch })
    .url(`${BaseUrl}/api/1/`)
    .headers({ Accept: 'application/json' })
    .catcher(422, accountPasswordCatcher)
    .middlewares([xsrfMiddleware]);

export default Client;

Usage:

import Client from '../services/Client';

Client.url('account').post({ email }).json().then(response => {
    console.log('ok')
});

But I get an unresolved error:

Unhandled Rejection (Error): {"message":"The given data was invalid.","errors":{"account_password":["The account password field is required."]}}

W:/src/resolver.ts:74
  71 | if (!response.ok) {
  72 |     return response[conf.errorType || "text"]().then(msg => {
  73 |         // Enhances the error object
> 74 |         const err = new Error(msg)
  75 | ^       err[conf.errorType || "text"] = msg
  76 |         err["status"] = response.status
  77 |         err["response"] = response

My question is, why doesn't my catcher catch the 422 error code? Is there something I don't understand?

elbywan commented 4 years ago

Hi @alexdemers,

My question is, why doesn't my catcher catch the 422 error code? Is there something I don't understand?

Hmm I see some issue with the way you wrote the catcher, but it would not explain why the exception does not get caught at all.

// async seems unnecessary - more details below
const accountPasswordCatcher = async (error: WretcherError) => {
        /* 
            This line looks incorrect:
            - by default, wretch assumes that an error body is text and only defines the error.text property.
              you can add the .errorType('json') to the method chain change the behaviour
            - error.text and error.json are not functions, and contain respectively a String or a parsed Object
            - since the text and json properties are already populated, there is no need to use await
        */ 
    const response = await error.json();
    if ('account_password' in response.errors) {
        console.log('test');
    }
};

I tried to reproduce on my end but it seems to work fine, here is the self-contained html file I used to test:

<!DOCTYPE html>
<html>
<head>
    <title>Wretch Test</title>
    <script type="module">
        import wretch from 'https://unpkg.com/wretch/dist/index.js'

        const middleware = next => (url, opts) => {
            console.log('Middleware…')
            return next(url, opts)
        }

        const catcher = error => {
            console.log('Caught!')
            return error.json
        }

        const client = wretch()
            .polyfills({ fetch: window.fetch })
            .url('https://httpstat.us')
            .headers({ Accept: 'application/json' })
            .catcher(422, catcher)
            .errorType('json')
            .middlewares([middleware])

        client.url('/422').get().json().then(response => {
        console.log(response)
        })
    </script>
</head>
<body></body>
</html>

Prints in the browser console:

Capture d’écran 2020-09-01 à 21 00 52