首页 > 解决方案 > Set node-fetch parameter dynamically

问题描述

For a unit test I am creating a new user via POST in my database, retrieving a id and token. After that I want to DELETE this user with the id, token I just received from the first fetch.

import fetch from 'node-fetch';

type Response = {
       status: number,
       body: any
};

const response = {} as Response;

someFunction(async () => {

    // Create new user
    await fetch('http://localhost:3000/api/user/register', {
        method: 'POST',
        body: JSON.stringify({email: 'user@test.com', password: 'test-password'}),
        headers: {'Content-Type': 'application/json'}
    }).then(res => {
            res.json().then(json => response.body = json);
        }
    );

    // Delete user just created
    await fetch('http://localhost:3000/api/user/' + response.body.id, {
        method: 'DELETE',
        headers: {
            'Content-Type': 'application/json',
            Authorization: 'Bearer ' + response.body.token
        }
    });
});

The first fetch runs successfully response.body.id and response.body.token are not empty but the second fetch always fails anyways with TypeError: Cannot read property 'id' of undefined

I would appreciate if someone could point out why. Thanks

标签: javascriptnode.jstypescriptnode-fetch

解决方案


The reason it happens is because you're mixing up some methods. When your first fetch fulfills it will call the first then() method. Inside of that you call the json() method of the response and chain the promise from there. Now the first then() did not get a returned value, so the fetch thinks it's finished. But in reality your res.json() promise could still be running.

All the while your second fetch request is already being called while res.json() is still resolving. That's why the value is undefined.

So await the first fetch and store the response. Then await the json() promise and store the result of that. Now your thread goes through each step without having a race condition.

The values from the JSON response will now be available in your second fetch request.

The second fetch doesn't have to use await. Only if you need the values from the response and need to do something whenever that request finishes.

someFunction(async () => {

    // Create new user
    const response = await fetch('http://localhost:3000/api/user/register', {
        method: 'POST',
        body: JSON.stringify({email: 'user@test.com', password: 'test-password'}),
        headers: {'Content-Type': 'application/json'}
    });

    const json = await response.json();

    // Delete user just created
    fetch('http://localhost:3000/api/user/' + json.id, {
        method: 'DELETE',
        headers: {
            'Content-Type': 'application/json',
            Authorization: 'Bearer ' + json.token
        }
    });
});

推荐阅读