Hi Everyone! I'm trying to implement SuiteQL to q...
# suitetalkapi
r
Hi Everyone! I'm trying to implement SuiteQL to query a workbook, but I'm having a really difficult time getting the api request to go through. I'm able to make test requests with Postman, but when I use the Oauth library, I get an 'INVALID_LOGIN' error. Has anyone else run into this problem? Has anyone had any success using Oauth to make SuiteQL queries via REST?
b
probably will need to share your code on this one
especially on what you are using to add the authorization
a
check that the role you're using has full REST permissions. It's separate from the SOAP Web Services.
r
Copy code
const crypto = require('crypto');
const OAuth = require('oauth-1.0a');
const fetch = require('node-fetch');

const oauth = OAuth({
	consumer: {
		key: '<CONSUMER_KEY>',
		secret: '<CONSUMER_SECRET>'
	},
	signature_method: 'HMAC-SHA1',
	hash_function(base_string, key) {
		return crypto
			.createHmac('sha1', key)
			.update(base_string)
			.digest('base64');
	}
});

const request_data = {
	url: 'https://<ACCOUNT_ID>.suitetalk.api.netsuite.com_sb1/services/rest/query/v1/suiteql?limit=5',
	method: 'POST',
	data: { q: 'SELECT * FROM Budget' }
};

const token = {
	key: '<TOKEN>',
	secret: '<TOKEN_SECRET>'
};

const auth = oauth.toHeader(oauth.authorize(request_data, token)).Authorization;

console.log('auth: ', auth);

fetch('https://<ACCOUNT_ID>.<http://suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=5|suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=5>', {
	method: 'POST',
	headers: {
		Authorization: auth,
		'Content-Type': 'application/json',
		Cookie: 'NS_ROUTING_VERSION=LAGGING',
		prefer: 'transient'
	},
	body: { q: 'SELECT * FROM budgets' }
}).catch(err => {
	console.error('err: ', err);
}).then(response => {
	console.log('response: ', response);
});
Using
oauth-1.0a
,
Authorization
looks like this:
Copy code
OAuth oauth_consumer_key="<CONSUMER_KEY>", oauth_nonce="9yOytqfYkgj9FT81fVoxp5CZRmINihBs", oauth_signature="dCwiMlJKjiJV0uAga4iLa6mG%2BCA%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1597946506", oauth_token="<TOKEN>", oauth_version="1.0"
With these results:
Copy code
Response {
  size: 0,
  timeout: 0,
  [Symbol(Body internals)]: {
    body: PassThrough {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      [Symbol(kCapture)]: false,
      [Symbol(kTransformState)]: [Object]
    },
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    url: 'https://<ACCOUNT_ID>.<http://suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=5|suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=5>',
    status: 401,
    statusText: 'Unauthorized',
    headers: Headers { [Symbol(map)]: [Object: null prototype] },
    counter: 0
  }
}
I've also tried to use
netsuite-rest
library:
Copy code
const NsApiWrapper = require('netsuite-rest');

const NsApi = new NsApiWrapper({
	consumer_key: '<CONSUMER_KEY>',
	consumer_secret: '<CONSUMER_SECRET>',
	token: '<TOKEN>',
	token_secret: '<TOKEN_SECRET>',
	realm: '<ACCOUNT_ID>'
});


NsApi.request({
	path: 'https://<ACCOUNT_ID>.suitetalk.api.netsuite.com_sb1/services/rest/query/v1/suiteql?limit=5',
	method: 'POST',
	body: `{"q":"SELECT * FROM budgets"}`
})
	.then(response => console.log(response))
	.catch(err => console.log(err));
Authorization looks like this:
Copy code
Authorization: 'OAuth realm="<ACCOUNT_ID>", oauth_consumer_key="CONSUMER_KEY", oauth_nonce="IwkuxaZeLvV69wmXBLG3LmxLz5dZVpnv", oauth_signature="4PrF4jMHTn8o9DxCs76%2BxpFLsGLb6zu5zmdH2OCvtfk%3D", oauth_signature_method="HMAC-SHA256", oauth_timestamp="1597948275", oauth_token="<TOKEN>", oauth_version="1.0"',
With this response:
Copy code
response: {
    statusCode: 401,
    headers: {
      date: 'Thu, 20 Aug 2020 18:31:19 GMT',
      'x-n-operationid': '0e4c8288-3d7f-447d-a1f8-f7022f522e81',
      ns_rtimer_composite: '996684085:706172746E6572733034332E70726F642E6368692E6E65746C65646765722E636F6D:80',
      'strict-transport-security': 'max-age=31536000',
      pragma: 'No-Cache',
      'cache-control': 'No-Cache',
      expires: '0',
      'edge-control': 'no-store',
      'www-authenticate': 'OAuth realm="<ACCOUNT_ID>", error="token_rejected", error_description="Invalid login attempt."',
      'content-type': 'application/vnd.oracle.resource+json; type=error; charset=UTF-8',
      'content-length': '193',
      'set-cookie': [Array],
      p3p: 'CP="CAO PSAa OUR BUS PUR"',
      vary: 'User-Agent',
      'keep-alive': 'timeout=10, max=983',
      connection: 'Keep-Alive'
    },
    data: {
      type: '<https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2>',
      title: 'Invalid login attempt, for more details see Login Audit Trail.',
      status: 401,
      'o:errorCode': 'INVALID_LOGIN'
    }
  }
}
@battk Thanks!!!
b
dont use the data parameter for your request data used in oauth.authorize
its form data only
use the realm parameter when you are creating your oauth object
you also want to stringify your body in your fetch parameters