3
respostas

Fetch method post em servidor externo com Token

Oi Pessoal, tudo bem?

Estou tentando aprender um pouco mais sobre requisições API externas com fetch e tenho a seguinte especificação de API para requisitar de um servidor de terceiros:

https://api.race-monitor.com/v2/Common/AppSections

HTTP Method: POST

Parameters: apiToken String

Output: { "Successful": boolean, "AppSections": [ { "Name": "string", "ID": int32 } ] }

Estou tetando fazer isso com o seguinte código:

    var tokenid = localStorage.getItem('racetokenid');

    const myRequest = new Request('https://api.race-monitor.com/v2/Common/AppSections',
        {
            method: 'POST',
            mode: 'no-cors',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
              },
            body: JSON.stringify({
                apiToken: tokenid
              })
        })

    fetch(myRequest)
        .then(response => {
            if (response.status === 200) {
                return response.json();
            } else {
                throw new Error('erro em no servidor.');
            }
        })
        .then(response => {
            console.debug(response);
            // ...
        }).catch(error => {
            console.error(error);
        });

Estou recebendo o erro abaixo:

POST https://api.race-monitor.com/v2/Common/AppSections 403 ()

Não sem se estou passando o parametro de apiToken de forma indevida ou se tenho que fazer essa request de uma forma diferente.

3 respostas

Fala Edmar, tudo bem ?

Creio eu que pode ser justamente a forma como está sendo enviada a informação do token. Perceba que o contrato da API não deixa claro que espera receber um JSON (como está sendo feito), o JSON é apenas a resposta da mesma para esse endpoint. A API não está recendo uma String com nome apiToken, mas sim um objeto no padrão JSON, que tem uma propriedade chamada apiToken.

Eu tentaria fazer da seguinte forma:

var tokenid = localStorage.getItem('racetokenid');

const data = new FormData();
data.append('apiToken', tokenid);

const requestDetails = {
    method: 'POST',
    mode: 'no-cors', // talvez não precise
    headers: new Headers({
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded' // talvez não precise
    }),
    body: data
}

fetch('https://api.race-monitor.com/v2/Common/AppSections', requestDetails)
    .then(...);

Talvez possa resolver.

Espero ter ajudado. Abraço!

Oi Rafael, tudo bem?

Também não funcionou dessa forma. Se eu faço pelo CURL com a sintaxe abaixo funciona:

curl https://api.race-monitor.com/v2/Common/AppSections --data "apiToken=NumeroDoToken"

Fala Edmar, tudo bem ?

O objeto de FormData faz com que a requisição seja enviada como um multipart/form-data. Alguns servidores aceitam esse conteúdo mesmo quando o esperado é application/x-www-form-urlencoded. Pelo jeito não é o caso do servidor que expõe essa API.

Fiz um teste com o curl: curl https://api.race-monitor.com/v2/Common/AppSections --data "apiToken=0A1B2C3D" --verbose.

Saída:

> POST /v2/Common/AppSections HTTP/2
> Host: api.race-monitor.com
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 14
> Content-Type: application/x-www-form-urlencoded
> 
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* We are completely uploaded and fine
< HTTP/2 403 
< date: Thu, 05 Apr 2018 18:12:16 GMT
< content-type: application/json; charset=utf-8
< content-length: 59

O server espera os parametros via form-url-encoded, via queryString em resumo. Por isso deve passar apiToken=123456, se houvessem outros parâmetros deveriamos usar aquele conhecido padrão apiToken=123456&outroParametro=outroValor.

Mas para não ficar montando esse padrão na mão (o que pode dar trabalho), dá pra usar objeto URLSearchParams que é específico pra esse caso.

Documentação => https://fetch.spec.whatwg.org/#ref-for-urlsearchparams%E2%91%A0

Imagino que dê pra fazer assim então:

var tokenid = localStorage.getItem('racetokenid')

const stringParams = `apiToken=${tokenid}`
const parameters = new URLSearchParams(stringParams)

// OU
// const parameters = new URLSearchParams()
// parameters.append('apiToken', tokenid)

const requestDetails = {
    method: 'POST',
    headers: new Headers({
        'Accept': 'application/json'
    }),
    body: parameters
}

fetch('https://api.race-monitor.com/v2/Common/AppSections', requestDetails)
    .then(...);

Espero ter ajudado. Abraço!