0

SOLUTION:

function REDCapImportRecord() {
  const url = 'https://redcap.INSTITUTION.edu/api/'

  const testdata = [{
    record_id: 'TEST123456',
    testfield: 'test'
  }]

  const body = new FormData();
  body.append('token', 'MYTOKEN');
  body.append('content', 'record');
  body.append('format', 'json');
  body.append('data', JSON.stringify(testdata));

  const params = {
    method: 'POST',
    body,
  }

return fetch(url, params)
  .then(data => {
    console.log('fetch data: ', data)
  })
  .catch(error => console.log('Error: ', error))
}

Original question:

I'm creating a React Native app to interface with REDCap and am having difficulty utilizing the API in Javascript.

I've enabled all privileges on REDCap, and I'm able to make calls successfully using PHP and in the REDCap API Playground.

For the app, I'm using fetch:

async function REDCapImport() {
  const url = 'https://redcap.med.INSTITUTION.edu/api/'

  const testdata = {
    record_id: 'TEST1234',
    test_field: 'TEST'
  }

  const params = {
    method: 'POST',
    token: 'MYTOKEN',
    content: 'record',
    format: 'json',
    type: 'flat',
    overwriteBehavior: 'normal',
    forceAutoNumber: false,
    data: JSON.stringify(testdata),
    returnContent: 'count',
    returnFormat: 'json',
  }

  return await fetch(url, params)
    .then(data => {
      console.log('fetch data: ', data)
    })
    .then(response => console.log('Response: ', response))
    .catch(error => console.log('Error: ', error))
  }

}

Here is the PHP that works:

<?php
$data = array(
    'token' => 'MYTOKEN',
    'content' => 'record',
    'format' => 'json',
    'type' => 'flat',
    'overwriteBehavior' => 'normal',
    'forceAutoNumber' => 'false',
    'data' => $testdata,
    'returnContent' => 'count',
    'returnFormat' => 'json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://redcap.med.upenn.edu/api/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data, '', '&'));
$output = curl_exec($ch);
print $output;
curl_close($ch);

I get a 403 error:

error

It seems even that in the params object, if I remove the API token it doesn't change the error -- it still returns 403.

It works just fine in PHP, so I feel like I'm doing something wrong as my token and privileges indeed work.

Any help about how to get this request to work in Javascript would be greatly appreciated. Thanks!

wibeasley
  • 5,000
  • 3
  • 34
  • 62
  • How are you making the request in php? Are you adding the token in the right place, ie some apis use headers set with tokens instead of as post parameters – Patrick Evans Jun 08 '19 at 05:41
  • @PatrickEvans I've added the php code to the question. I can also add sample code for Perl/Python/Ruby/Java if it would be helpful – Nadir Bilici Jun 08 '19 at 14:31

1 Answers1

3

You are putting your data in the wrong place in your js. The fetch() method's second argument is a settings object not a direct data object. Your data needs to go onto a property of that settings object specifically the body property. It can be in a few different structures blob,FormData,query string etc.

So you would do something like:

let data = new FormData();
data.append('token','your token');
data.append('format','json');
data.append('data',JSON.stringify(testData));
/* etc, keep appending all your data */

let settings={
  method:'post',
  body:data
};
fetch('url',settings)
Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
  • That solved it -- I've posted the working code up top. Thanks so much! – Nadir Bilici Jun 09 '19 at 05:54
  • Is there any way to send this request without FormData? It sends multipart request if we use the FormData. I want use this as simple post request with application/x-www-form-urlencoded content type. – Bharat Rathavi Jan 23 '22 at 11:40
  • 1
    @RathviBharat yes, just set `data` to a query string eg `field1=6&field2=20` or create a [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams) object with your data. If you use just a plain query string for `data` you have to manually set the content-type header to be `application/x-www-form-urlencoded`, it should automatically do that if you use a `URLSearchParams` object though – Patrick Evans Jan 23 '22 at 12:55