Errors when trying NetSuite's Restlet interface: datain is null - netsuite

I'm trying out Restlets for the first time and I am having trouble returning any data.
I've built a basic restlet and deployed it in NetSuite. The code is as follows:
function getRESTlet(dataIn) {
return nlapiLoadRecord(dataIn.recordtype, dataIn.id); // e.g recordtype="customer", id="769"
}
Using Chromes' REST Console application I've set up the following:
Request URI: https://rest.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1&recordtype=customer&id=2409
Request Headers: NLAuth nlauth_account=123456,nlauth_email=email#emailaddy.com,nlauth_signature=password
Running it as a GET operation I return the following error:
error code: JS_EXCEPTION
error message:type
Followed by the following email:
Date & Time: 8/19/2013 2:48 pm
Execution Time: 0.06s
Script Usage: 0
Script: getRecord
Type: RESTlet
Function: getRESTlet
Error: SSS_MISSING_REQD_ARGUMENT
type
Stack Trace: getRESTlet(getCustomer.js:14)
restletwrapper(null$lib:3)
The customer record exists, the RestLet code is from the NetSuite help system, and I get an error email when the script fails so I know the deployment URL is good.
Any ideas on what I'm doing wrong?
--EDIT--
Changing my function signature to function getRESTlet(type,dataIn) resolves the type error, although now I get:
error code: UNEXPECTED_ERROR
error message:TypeError: Cannot read property "recordtype" from undefined (getCustomer.js#14)
I've also removed customer and id from the request URI and instead listed them in the Request Payload section of REST Console.
--Edit 2--
adding nlapiLogExecution('DEBUG', 'JSON.stringify(datain) is:', JSON.stringify(datain)); to the function is returning blank for the log entry. It appears that datain is null....

I had a similar issue that was resolved once I set the request header content-type to application/json.
The default content-type is text/plain which passes a stringified JSON object to the function and expects a string to be returned.
If you set the content-type to application/json or application/xml the 'datain' parameter will come in as a javascript object.
From the NetSuite Docs:
If users specify a content type other than JSON or TEXT, a 415 error
is returned with the following message:
Invalid content type. You can
only use application/json, application/xml or text/plain with
RESTlets.
If users provide data in a format different from specified
type, the following error is returned with one of the following
messages:
Error code = INVALID_RETURN_DATA_FORMAT Error message =
Invalid data format. You should return TEXT. Error message = Invalid
data format. You should return a JavaScript object.

To fix the error of
Error code = INVALID_RETURN_DATA_FORMAT Error message =
Invalid data format. You should return TEXT. Error message = Invalid
data format. You should return a JavaScript object.
You can supply a Content-type to the get specified get request of 'json'. Documentation would seem to indicate that you should specify "accepts" json, but for me only the content-type on a get made the request work.

I got this error: SSS_MISSING_REQD_ARGUMENT when trying to submit a transform record type that I had specified in camel case rather that all lower case... took me a day to work that out :(

changing the function to:
function getRESTlet(datain) {
return nlapiLoadRecord(datain.recordtype, datain.id); // e.g recordtype="customer", id="769"
}
resolves the issue. I thought I had tried without camelCase, but alas I did not.
So moral of the story is: datain is case sensitive!

Related

Do guidelines exist for the second parameter of `response.writeHead` when submitting the errored response to client?

I tried to send the below message
Invalid query parameters detected:
=== Error No. 1 ==========
Required property is missing
● Property / element: 'Deserialized query parameters of http://127.0.0.1:90/api/categories route.paginationPageNumber'
This property is 'undefined' while has been marked as required.
● Property / element specification:
{
"type": "number",
"required": true,
"numbersSet": "NATURAL_NUMBER"
}
● Actual value: undefined
● Value before first pre-validation modification: undefined
< etc. >
via
response. // (is "http.ServerResponse")
writeHead(HTTP_StatusCodes.badRequest, errorMessage).
end();
in errorMessage variable . Below NodeJS error occured:
Caught error:
TypeError [ERR_INVALID_CHAR]: Invalid character in statusMessage
at new NodeError (node:internal/errors:371:5)
at ServerResponse.writeHead (node:_http_server:322:11)
// ...
I have no idea on which character NodeJS complains about (possibly slashes), but I suppose what I am using the second parameter of writeHead improperly. If so, there are two questions:
Which errorMessage must be like? Just "Bad request" or "Unauthorized"?
Where I should append above login message instead?
You can refer to this for official documentation
You can send a response like this
let body = error_message; // or whatever response you want to send back to the sender
response
.writeHead(STATUS_CODE, {
'Content-Type': 'your_header_content_type'
}).end(body);
As for the status codes, you can refer the mozilla convention here (which is quite widely used)

axios.post() error about circular structure

Please guide me in case I'm not in proper use of axios. This simple piece of code can directly run:
const axios = require('axios')
axios.post('https://exp.host/--/api/v2/push/send', {"to":["ExponentPushToken[xxxxxxx]"],"title":"test title","body":"test body."})
.then(responseExpo => {
console.log("expo replied normally: " + JSON.stringify(responseExpo));
})
.catch(error => {
console.log("expo replied with error: " + JSON.stringify(error,null,4));
});
The result is:
Promise { <pending> }
expo replied with error: {}
"axios": "^0.19.2"
I tried to post with api tools and see a response with normal 200 status code:
{
"data":[
{
"status": "error",
"message": "\"ExponentPushToken[xxxxxxx]\" is not a registered push notification recipient",
"details":{
"error": "DeviceNotRegistered"
}
}
]
}
(you may ignore the "error": "DeviceNotRegistered" inside this json cos it's expected because I have put an invalid xxxxx input value when calling the api. Even putting a valid input value the result is still returning to the catch block with empty error)
I'm expecting it to return to the then block cos the server actually response with 200 with well formatted json result.
Have I done something wrong so that the call returns to the catch block? Cos the error is empty I have no idea what went wrong.
===============================
after jfriend's reminder I changed to directly disply the error.
console.log("expo replied with error: " + error);
it is show like this now:
Promise { <pending> }
expo replied with error: TypeError: Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle
Anyone can let me know what exactly it means and guide me how to correct my usage?
(problem resolved). the response (responseExpo in the question) is neither a plain data JSON nor a plain string. it is an object with (see github.com/axios/axios#response-schema) some attributes. The real response content is inside "response.data". I was wrongly treating the response to be a plain json object or the http response content.
I had a similar problem and as solution, I used HttpService from nestjs which returns Observable<AxiosResponse<T>>. I fixed the problem by piping and plucking the request like this:
http.put<T>(url, data, config).pipe(pluck('data'))
I had a similar problem with HttpService from nestjs which returns Observable<AxiosResponse<any>>. I resolve with:
this.httpService.post(this.legacyAccessTokenEndpoint, form, { headers: form.getHeaders() }).pipe(map(x => x?.data))

MongoDB won't save JSON document?

Quick question, but does anyone have a clue why MongoDB won't save the following document? I'm using MongoJS in NodeJS to connect to MongoDB and using the following lines of code to save (in my JS file, the function call is underneath the variable definition). The save function doesn't save, but automatically goes to the callback function.
Any thoughts? Thanks so much :).
Edit:
After adding an error log to the callback, I'm getting the following error:
{ [MongoError: error parsing element 0 of field documents :: caused by :: wrong type for '0' field, expected object, found 0: "{"Word":"Count","read":1,"letter":1,"wh":1,"urging":2,"swift":1,"approval":1,"add'l":1,"lease":1,"space":1,"fayetteville":1,"vamc":1,"vets":2,"care":1..."]
name: 'MongoError',
ok: 0,
errmsg: 'error parsing element 0 of field documents :: caused by :: wrong type for \'0\' field, expected object, found 0: "{"Word":"Count","read":1,"letter":1,"wh":1,"urging":2,"swift":1,"approval":1,"add\'l":1,"lease":1,"space":1,"fayetteville":1,"vamc":1,"vets":2,"care":1..."',
code: 9 }
db.collection.save(json_buffer, function() {
console.log("Complete");
});
var json_buffer = {"Word":"Count","read":1,"letter":1,"wh":1,"urging":2,"swift":1,"approval":1,"add'l":1,"lease":1,"space":1,"fayetteville":1,"vamc":1,"vets":2,"care":1,"#gnip":3,"--":3,"delivering":3,"data":3,"happy":3,"customers":3,"outrageous":1,"france":1,"sell":1,"warships":1,"putin":1,"#senatorkirk":1,"#repkinzinger":1,"#usrepkeating":1,"&amp":5,"urge":1,"strong":1,"action":3,"polling":1,"shows":1,"race":1,"close":1,"pitch":1,"pre-primary":1,"deadline":1,"goal":2,"joining":1,"#teamcavuto":1,"shortly":1,"discuss":1,"can’t":1,"continue":1,"punt":1,"debt":2,"crisis":1,"road":1,"watch":1,"opening":1,"remarks":1,"today’s":1,"senate":1,"committee":1,"hearing":1,"mcdonald":1,"nomination":1,"urged":1,"passage":1,"#summermealsact":2,"yesterday":1,"#monticello":1,"#ny--so":1,"impt":1,"expand":1,"#usda's":1,"summer":2,"nutrition":1,"program":1,"great":2,"catch":1,"high":1,"school":2,"friend":1,"john":1,"choate":1,"today":7,"family":1,"capitol":1,"hill":1,"child":1,"america":1,"wake":1,"day":1,"wondering":1,"eat":1,"nebraska":1,"communities":1,"access":1,"local":1,"tv":1,"programming":1,"introduced":1,"bill":4,"work":2,"past":1,"time":2,"congress":1,"meaningful":1,"reduce":1,"threat":1,"cyber":1,"attacks":1,"#mercnews":1,"op-ed":1,"fitting":1,"#us_sfrc":1,"passed":1,"#crpd":1,"bob":1,"dole's":1,"bday":1,"#disabilitytreaty":1,"advocate":1,"beginning":1,"#isupportcrpd":1,"senator":1,"mcconnell":2,"co-sponsors":1,"protect":2,"correctional":1,"officers":2,"daily":1,"independent":2,"#ashland":1,"#kentucky":1,"millions":1,"children":2,"recv":1,"free":1,"reduced":1,"meals":1,"year":1,"left":1,"hungry":1,"months":1,"unacceptable":1,"rt":5,"#aterkel":1,"record":1,"phone":1,"#senschumer":1,"…":1,"good":1,"meeting":1,"anne":1,"rung":1,"nominee":1,"#ombpress":1,"office":2,"fed":1,"procurement":1,"policy":1,"cc":1,"#senatehsgac":1,"#federalreserve":1,"divert":1,"leftover":1,"funds":1,"foreclosure":1,"review":1,"hardest":1,"hit":1,"fund":1,"#ri":1,"supports":1,"corrections":1,"prisons":1,"manchester":1,"pine":1,"knot":1,"ashland":1,"inez":1,"lex":1,"miami":1,"valley":1,"well-run":1,"base":1,"makes":1,"wright-patt":1,"#1":1,"airmen":1,"#gopoversight":1,"release":1,"#irs":2,"needed":1,"days":1,"confirm":1,"lerner":1,"hard":2,"drive":1,"crash":2,"provide":1,"support":3,"runaway":1,"homeless":1,"youth":1,"victims":1,"trafficking":1,"#housefloor":1,"tomorrow":1,"glad":1,"signature":1,"industry":1,"#kydistillers":1,"#repandybarr":1,"obama":1,"meant":1,"flexibility":1,"re-elected":1,"thoughts":1,"prayers":1,"affected":1,"fires":1,"tooele":1,"pray":1,"staying":1,"safe":1,"#utpol":1,"hr":1,"passes":1,"house":1,"#repderekkilmer":1,"modernize":1,"labs":1,"fyi":1,"fun":1,"activities":1,"hosted":1,"google":1,"young":1,"inventors":1,"age":1,"13+":1,"choose":1,"projects":1,"virtual":1,"field":1,"trips":1,"joined":1,"nyc":1,"workforce":2,"development":2,"hosting":1,"roundtable":1,"#bronx":1,"failure":1,"disclose":1,"timely":1,"manner":1,"destroyed":1,"critical":1,"evidence":1,"reason":2,"special":1,"prosecutor":1,"26%":1,"texas":1,"live":1,"poverty":1,"#raisethewage":1,"#honorflightact":2,"codify":1,"process":1,"tsa":1,"expedited":1,"dignified":1,"screening":1,"veterans":1,"visiting":1,"war":1,"memorials":1,"humbled":1,"join":2,"medal":1,"honor":1,"recipient":1,"staff":1,"sergeant":1,"ryan":1,"pitts":1,"nashua":1,"ceremony":1,"pentagon":1,"icymi":1,"statement":1,"halbig":1,"burwell":1,"#ecpzachevans":1,"save":1,"date":1,"mt":1,"#shrinersfest":1,"dates":1,"announced":1,"shrinersfest":1,"june":1,"25-28":1,"feat":1,"#blueangels":1,"htt…":1,"unleash":1,"america's":1,"energy":2,"abundance":1,"create":1,"#jobs":1,"economic":1,"growth":1,"affordable":1,"#yes2energy":1,"marks":1,"#100days":1,"nigerian":1,"schoolgirls":1,"kidnapping":1,"forgotten":1,"#bringbackourgirls":1,"pleased":1,"mayor":1,"#rahmemanuel":1,"taking":1,"#fly2ohare":1,"noise":1,"measure":1,"seeks":1,"pay":1,"gratitude":1,"group":1,"americans":1,"make":1,"ultimate":1,"sacrifice":1,"stopped":1,"dutch":1,"embassy":1,"offer":1,"condolences":1,"lost":1,"loved":1,"#mh17":1,"#obamafailures":1,"min":1,"#131":1,"odds":1,"drives":1,"irs":1,"claims":1,"win":1,"fl":1,"lottery":1,"times":1,"#tcot":1}
Struggled with this for a long time, despite reading up here. Actual cause of the issue finally turned out to be that the JSON object I was trying to update was 'undefined'. Try catching the mongo error and printing the entire error object.
The JSON object was being considered as undefined in my case because it was actually an array, not an object. So I tried doing a mongo update on myJsonObject[0] rather than myJsonObject which was actually an array, and this succeeded.
Do a console.log of the stringified json 'object' you are trying to save, and if it's surrounded by square braces, then you know you're dealing with an array, and need to work on its element(s) instead.
I had this error when:
Create JSON object in client code
Send it over http request
Get it from the request body in node code
Send the body content to mongodb
The problem was the object sent was a String, not a JSON object...
Using var json = JSON.parse(json-string-from-body) and send json solve my problem.
Also, I used insert() method not save(). In mongodb console save({"htt…":1}) which is a part of your data return an error but insert({"htt…":1}) works fine.
I got this error with Mongoose when doing
Model.update(docId, {...})
when I should have been doing
Model.update({_id: docId}, {...})

Can I get HttpStatusCode while in ServiceStack ResponseFilter?

While in the ResponseFilters is there anyway to get the status code (and description) which is going back to the client?
Long explanation:
I'm looking into adding a response header while I'm in a response filter. The issue is that in our API we set on some NotFound & BadRequest returns a message for the user in the status description;
return HttpError.NotFound(string.Format("Not found with TicketCodeId {0}",
request.TicketCodeId))
This works great in android and .net clients of all sorts.
But some clients (I'm looking at you iphone) don't get the status description. The idea is to see in the responsefilter that the status code is set to 400 range and it has a special message, then add a header and copy the status message description into it.
Problem is ResponseFilter has access to IHttpResponse, and that object has only a setter to the statuscode (so no way for me to determine if I need to add the header).
I want to solve it in this generic way to avoid having to remember (and go back over all service implementations) everywhere a 400 status code is set to add the same description to a header. It would be nice if this is done in a single place, the ResponseFilter.
ResponseFilter documentation
Since we are returning all responses with BadRequest and NotFound where we use a message in the status description as either an HttpError or HttpResult (which both are of type IHttpResult) I can do the following to create the desired extra header:
// Add Filter: If result is of type IHttpResult then check if the statuscode
// is 400 or higher and the statusdescription is set.
this.ResponseFilters.Add((req, res, dto) =>
{
if (dto == null) return;
var httpResult = dto as IHttpResult;
if (dto is IHttpResult)
{
// If statuscode is 400 then add a Header with the error message;
// this since not all clients can read the statusdescription
if ((int)httpResult.StatusCode >= 400)
AddPmErrorMessageHeader(res, httpResult.StatusDescription);
}
});
The AddPmErrorMessageHeader method will do some extra validation and use the res object to add the header:
res.AddHeader("PmErrorMessage", statusDescription);
I did some testing with the res.OriginalResponse but that somehow always has the StatusCode set to 200, even when just before setting the 4** status code.

CouchDB list "An error occured accessing the list: Invalid JSON" error

I'm trying to call a CouchDB list from JavaScript.
My jQuery call is:
var listItems = $.couch.db('foo').list('foo/barList', 'foo/barView');
If I test this in the FireBug console when I'm on a page that has jquery.couch.js loaded (like Futon) it returns exactly what I want it to (several <input> tags with the appropriate data populated).
However, when I call this from code, I get the error:
An error occured accessing the list: Invalid JSON: [the html]
... where [the html] is the html I want to manipulate in my script. I don't understand why I'm getting a JSON error - I thought the point of lists was to return HTML. Is there a way to force it to return my html to me?
Also, my list function includes the following, so I'm not sure why this doesn't work.
start({
"headers": {
"Content-Type": "text/html"
}
});
According to https://issues.apache.org/jira/browse/COUCHDB-1059 this was a recognized bug and it had been patched. However after making the changes in jquery.couch.js recommended by Jan Lehnardt on the above page, I had to do one thing further.
The page above recommends making the following change in jquery.couch.js :
- var resp = httpData(req, "json");
+ var resp = httpData(req, dataType);
For some reason this didn't work for me but it did when I instead replaced it with the following. Theoretically one could add handlers for different types of content-types below.
var cType = req.getResponseHeader('Content-Type');
switch(cType) {
case 'text/html':
var resp = req.responseText;
break;
default:
var resp = $.parseJSON(req.responseText);
break;
}
If I'm missing something, I welcome recommendations on how to do this more effectively, but this works for me.

Resources