axios.put('http://localhost:3000/api/userDatas/findUserAddProp',{
params: {
userId: "5bb8c3bd16bf1f515ce5b42f",
prop: "questions",
questionId: "5bb8c466cb49d8421c05eeda"
}
});
Server
Userdatas.findUserAddProp = function(req, res, cb) {
const queryId = req.query.userId;
const propToUpdate = req.query.prop;
const questionId = req.query.questionId;
console.log("queryId: ", queryId);
console.log("propToUpdate: ", propToUpdate);
console.log("questionId: ", questionId);
...
}
Here is the the server output on the console.
queryId: undefined
propToUpdate: undefined
questionId: undefined
Why is that happening i just passed all params to the server?
the put method expects an extra parameter "data" (sent in request body):
axios.put(url[, data[, config]])
pass it as null and you're done:
axios.put('http://localhost:3000/api/userDatas/findUserAddProp', **null,** {
...
You can open Axios Interface
put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
The Put method recieve the config after the data so you can do:
axios.put('http://localhost:3000/api/userDatas/findUserAddProp',
// Add null here in the data,
null,
// then you can give params in the config
{ params: { /* your params goes here */ }
});
Did you try
req.params.userId
req.param is used to read Url Params like /user/:id whereas req.query is used to read query parameters like http:localhost:8080/api/users?id=123
Related
I've run into some error while trying to perform near-api-js viewFunction.
I've made a script to check for storage balance of an accountId parse from the API body.
When i receive the accountId parse from the API i parse into this ftGetStorageBalance function, from there the args: { account_id: accountId } is parse to accountViewFunction.
Here are the functions:
async ftGetStorageBalance(
tokenId: string,
accountId: string,
): Promise<FTStorageBalance | null> {
try {
const config = await this.getDefaultConfig();
const connection = await this.getConnect(config);
const account = await this.getAccount(this.nearCfg.accountId, connection);
return this.accountViewFunction(
{
methodName: 'storage_balance_of',
args: { account_id: accountId },
},
account,
tokenId,
);
} catch (e) {
throw new Error(e);
}
}
Here is the function when the error hits:
async accountViewFunction(
{ methodName, args }: ViewFunctionOptions,
account: nearAPI.Account,
contractId: string,
): Promise<any> {
// retrieve account_id from args
//access the first key in the args
// const key = Object.keys(args)[0];
// retrieve the value of the key
// const accountId = args[key];
// const jsonArgs = { account_id: accountId };
// const test = `{ "account_id" : "${accountId}" }`;
// const jsontest = JSON.parse(test);
// console.log(jsontest);
// const bufferArgs = Buffer.from(JSON.stringify(jsonArgs));
return account.viewFunction(contractId, methodName, args);
}
I've tried console.log the args and here's what i get:
{ account_id: 'phuocsrp3.testnet' }
In the near-api-js library, it said that the args should be wrapped in JSON.
* Invoke a contract view function using the RPC API.
* #see {#link https://docs.near.org/docs/develop/front-end/rpc#call-a-contract-function}
*
* #param contractId NEAR account where the contract is deployed
* #param methodName The view-only method (no state mutations) name on the contract as it is written in the contract code
* #param args Any arguments to the view contract method, wrapped in JSON
* #param options.parse Parse the result of the call. Receives a Buffer (bytes array) and converts it to any object. By default result will be treated as json.
* #param options.stringify Convert input arguments into a bytes array. By default the input is treated as a JSON.
* #returns {Promise<any>}
*/
viewFunction(contractId: string, methodName: string, args?: any, { parse, stringify }?: {
parse?: typeof parseJsonFromRawResponse;
stringify?: typeof bytesJsonStringify;
}): Promise<any>;
So i've tried parse into the accountViewFunction the json format with JSON.stringify(jsonArgs) stuff in the above script or even the Buffer.from(JSON.stringify(jsonArgs)) but it runs into the error stacks:
TypedError: [-32700] Parse error: Failed parsing args: missing field account_id
at /Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/near-api-js/lib/providers/json-rpc-provider.js:329:31
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Object.exponentialBackoff [as default] (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/near-api-js/lib/utils/exponential-backoff.js:7:24)
at JsonRpcProvider.sendJsonRpc (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/near-api-js/lib/providers/json-rpc-provider.js:304:26)
at JsonRpcProvider.query (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/near-api-js/lib/providers/json-rpc-provider.js:116:22)
at Account.viewFunction (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/near-api-js/lib/account.js:366:24)
at NearUtilsService.singleCheckStorageAndSendToken (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/src/application/near/utils/near.utils.service.ts:478:28)
at NearController.testsend (/Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/src/application/near/near.controller.ts:58:20)
at /Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/#nestjs/core/router/router-execution-context.js:46:28
at /Users/phuocha/Documents/phuoc_dev/work/starpunk-crosschain-starpad/node_modules/#nestjs/core/router/router-proxy.js:9:17 {
type: 'UntypedError',
context: undefined
}
The above functions works well in Powershell but somehow it fails in macos environment.
Here is info about my env:
Nodejs version: 14.18.3
Near-api-js: 0.44.2
Nestjs: 8.0.0
The above scripts I've taken a reference from:
https://github.com/ref-finance/ref-ui/blob/main/src/services/near.ts
Please help!
We debugged this in office hours, the error was arising from using an undefined value in the contractId variable.
There are no problems with the arguments (args). You are using the token_id as the contractId when you call your viewFunction(). Maybe you can pass the correct contractId instead?
// Signature is fine. It expects a contractId, but you pass a tokenId when you call it.
accountViewFunction({ methodName, args },account,contractId){
return account.viewFunction(contractId, methodName, args);
}
this.accountViewFunction({
methodName: 'storage_balance_of',
args: { account_id: accountId },
},
account,
tokenId, // <-- you use this as contractId.
);
Try to pass the contractId instead
this.accountViewFunction({
methodName: 'storage_balance_of',
args: { account_id: accountId },
},
account,
this.contract.contractId, // <-- Use the contract's contractId
);
I have two files, one is api.js and other one is handler.js. For schema handling I am using celebrate module #hapi/joi
On api.js I wrote only the API name
On handler.js I wrote the API functionality.
api.js
//JOI Schema Validator Middleware.
router.use(celebrate({
body: Joi.object().keys({
post: Joi.string().max(10),
userid: Joi.string(),
})
}));
const handler = require('./handler');
router.post('/createpost', handler.createPost);
router.use(errors());
module.exports = router;
By this if error happens then i got the Response like this
{"statusCode":400,"error":"Bad Request","message":"child \"post\" fails because [\"post\" length must be less than or equal to 10 characters long]","validation":{"source":"body","keys":["post"]}}
I just want to Convert this error into my own format error i.e something like this
{error: true, status: 500, message: 'validation error', version: x.x.2}
The default joi error is generated through router.use(errors()); this module. How I modify this?
Any help or suggestion is really appreciated.
TL;DR: Create your own 'errors()' function.
You have probably managed to change it by now, but just like me, I had the exact same issue and found this answerless thread.
Well, for future readers, celebrate errors() is nothing else than a function, more exactly, this one:
(err, req, res, next) => {
// If this isn't a Celebrate error, send it to the next error handler
if (!isCelebrate(err)) {
return next(err);
}
const {
joi,
meta,
} = err;
const result = {
statusCode: 400,
error: 'Bad Request',
message: joi.message,
validation: {
source: meta.source,
keys: [],
},
};
if (joi.details) {
for (let i = 0; i < joi.details.length; i += 1) {
const path = joi.details[i].path.join('.');
result.validation.keys.push(EscapeHtml(path));
}
}
return res.status(400).send(result);
}
There, you can see the response object 'result' being declared and how it's done. So, to change the output of it, you have to not use errors() and create your own function to handle it.
So, I declared a new function:
private errorHandling = (err, req, res, next) => {
if (isCelebrate(err)) {
return res.send({
statusCode: 400,
message: err.joi.message
});
}
return next(err);
}
You can obviously change the above to suit your needs.
Update
Celebrate changed their error structure to a CelebrateError, now you need access the error details using:
const errorBody = err.details.get('body'); // 'details' is a Map()
const { details: [errorDetails] } = errorBody;
instead of the err.joi. The message property remains the same.
Then, instead of using app.use(errors()) I used app.use(this.errorHandling), and now I get the celebrate response formatted as I want to.
After some research, I found out it can be solved 2 ways:
[Segments.BODY]: Joi.object().keys({
value: Joi.string().required().error(new Error('Value is required and has to be a text!')),
})
or
[Segments.BODY]: Joi.object().keys({
password: Joi.string().required().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).min(8).label('Password').messages({
'string.pattern.base': 'Your {#label} does not matche the suggested pattern',
'string.base': `Your {#label} should match the suggested pattern`,
'string.empty': `Your {#label} can not be empty`,
'string.min': `Your {#label} has to be at least {#limit} chars`,
'any.required': `Your {#label} is required`,
}),
})
I am calling the GetEntity OData read method from the SAP UI5 view controller and passing a key value in the request URL. I am getting the proper response from the back-end when I hardcode the key value.
However, when I try to pass the key value dynamically in a variable by appending it to the URL, it doesn't work. I get the following error
HTTP request failed 404
In below code, sGrant is the variable and it doesn't work. But if I replace the variable name with its value hard-coded in below code, for example, in the read method like this: "/GrantMasterSet('TY560003')", then it works:
var sGrant = this.byId("grantNbr").getValue();
var oMod = this.getOwnerComponent().getModel();
oMod.read("/GrantMasterSet('sGrant')", {
success: function(oData) {
var oJsonModel = new JSONModel();
oJsonModel.setData(oData);
this.getView().setModel(oJsonModel);
}.bind(this),
error: function(oError) {
MessageToast.show("Read Failed");
}
});
UI5 has a method to generate the right URI for you, no matter what is the data type of the key of your entity type.
The method is createKey of the sap.ui.model.odata.v2.ODataModel class. See its documentation
Inside your controller, use the following source code.
onInit: function () {
var oRouter = this.getOwnerComponent().getRouter();
oRouter.getRoute("routeName").attachPatternMatched( this.onPatternMatched , this );
},
onPatternMatched: function(oEvent){
var oParameters = oEvent.getParameters();
var oArguments = oParameters.arguments; // is not a function - without ()
var sKey = oArguments.id; // route parameter passed when using navTo
var oDataModel = this.getView().getModel(); // v2.ODataModel
oDataModel.metadataLoaded().then(function() {
var sPath = oDataModel.createKey("EntitySet", { Key: sKey });
this.getView().bindElement("/" + sPath);
}.bind(this)
);
}
Usually this is necessary in details pages, in order to apply element binding to a page. As the createKey method relies on the $metadata of your service, you must make sure that it is already loaded in your app. This can be achieved by using method metadataLoaded, provided in the snippet as well.
You should concatenate the variable to the rest of the string, like this:
oMod.read("/GrantMasterSet('" + sGrant + "')", {
Or, you can use a template literal, which comes down to the same thing (notice the backtics):
oMod.read(`/GrantMasterSet('${sGrant}')`, {
You should escape 'sGrant' so it can be evaluated.
It should be something like that :
var sGrant = this.byId("grantNbr").getValue();
var oMod = this.getOwnerComponent().getModel();
oMod.read("/GrantMasterSet("+sGrant+")", {
success: function(oData) {
var oJsonModel = new sap.ui.model.json.JSONModel();
oJsonModel.setData(oData);
this.getView().setModel(oJsonModel);
}.bind(this),
error: function(oError) {
MessageToast.show("Read Failed");
}
});
lets say I have a Backbone Model and I create an instance of a model like this:
var User = Backbone.Model.extend({ ... });
var John = new User({ name : 'John', age : 33 });
I wonder if it is possible when I use John.save() to target /user/create when I use John.save() on second time (update/PUT) to target /user/update when I use John.fetch() to target /user/get and when I use John.remove() to target /user/remove
I know that I could define John.url each time before I trigger any method but I'm wondering if it could be happen automatically some how without overriding any Backbone method.
I know that I could use one url like /user/handle and handle the request based on request method (GET/POST/PUT/DELETE) but I'm just wondering if there is a way to have different url per action in Backbone.
Thanks!
Methods .fetch(), .save() and .destroy() on Backbone.Model are checking if the model has .sync() defined and if yes it will get called otherwise Backbone.sync() will get called (see the last lines of the linked source code).
So one of the solutions is to implement .sync() method.
Example:
var User = Backbone.Model.extend({
// ...
methodToURL: {
'read': '/user/get',
'create': '/user/create',
'update': '/user/update',
'delete': '/user/remove'
},
sync: function(method, model, options) {
options = options || {};
options.url = model.methodToURL[method.toLowerCase()];
return Backbone.sync.apply(this, arguments);
}
}
To abstract dzejkej's solution one level further, you might wrap the Backbone.sync function to query the model for method-specific URLs.
function setDefaultUrlOptionByMethod(syncFunc)
return function sync (method, model, options) {
options = options || {};
if (!options.url)
options.url = _.result(model, method + 'Url'); // Let Backbone.sync handle model.url fallback value
return syncFunc.call(this, method, model, options);
}
}
Then you could define the model with:
var User = Backbone.Model.extend({
sync: setDefaultUrlOptionByMethod(Backbone.sync),
readUrl: '/user/get',
createUrl: '/user/create',
updateUrl: '/user/update',
deleteUrl: '/user/delete'
});
Are you dealing with a REST implementation that isn't to spec or needs some kind of workaround?
Instead, consider using the emulateHTTP option found here:
http://documentcloud.github.com/backbone/#Sync
Otherwise, you'll probably just need to override the default Backbone.sync method and you'll be good to go if you want to get real crazy with that... but I don't suggest that. It'd be best to just use a true RESTful interface.
No you can't do this by default with backbone. What you could to is to add to the model that will change the model url on every event the model trigger. But then you have always the problem that bckbone will use POST add the first time the model was saved and PUT for every call afterward. So you need to override the save() method or Backbone.sync as well.
After all it seems not a good idea to do this cause it break the REST pattern Backbone is build on.
I got inspired by this solution, where you just create your own ajax call for the methods that are not for fetching the model. Here is a trimmed down version of it:
var Backbone = require("backbone");
var $ = require("jquery");
var _ = require("underscore");
function _request(url, method, data, callback) {
$.ajax({
url: url,
contentType: "application/json",
dataType: "json",
type: method,
data: JSON.stringify( data ),
success: function (response) {
if ( !response.error ) {
if ( callback && _.isFunction(callback.success) ) {
callback.success(response);
}
} else {
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
},
error: function(mod, response){
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
});
}
var User = Backbone.Model.extend({
initialize: function() {
_.bindAll(this, "login", "logout", "signup");
},
login: function (data, callback) {
_request("api/auth/login", "POST", data, callback);
},
logout: function (callback) {
if (this.isLoggedIn()) {
_request("api/auth/logout", "GET", null, callback);
}
},
signup: function (data, callback) {
_request(url, "POST", data, callback);
},
url: "api/auth/user"
});
module.exports = User;
And then you can use it like this:
var user = new User();
// user signup
user.signup(data, {
success: function (response) {
// signup success
}
});
// user login
user.login(data, {
success: function (response) {
// login success
}
});
// user logout
user.login({
success: function (response) {
// logout success
}
});
// fetch user details
user.fetch({
success: function () {
// logged in, go to home
window.location.hash = "";
},
error: function () {
// logged out, go to signin
window.location.hash = "signin";
}
});
I try to post some data via json objects to my asp.net mvc view, here is the code
$("#submitButton").click(function () {
var name = $("#name")[0].valueOf();
var price = $("#price").valueOf();
var url = $("#url").valueOf();
var product = { Name: name, Price: price, Url: url };
$.post("/Home/NewProduct", product, function (json) { $('ul.items').append("<li><img src=" + url + "/></li>"); },"json");
});
and now, the result is an error:
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: http://localhost:1804/Scripts/jquery-1.4.2.min.js :: f :: line 132" data: no]
I try JQuery 1.4.1 and 1.4.2, If I try this code the error is the same
$.ajax({
type: "POST",
url: "/Home/NewProduct",
dataType: "json",
data: { Name: name, Price: price, Url: url },
success: function () { $('ul.items').append("<li><img src=" + url + "/></li>"); }
});
What I'm doing wrong? Please help!
Thanks!
To get the value of an input type element, use .val() instead of .valueOf(), like this:
var name = $("#name").val(),
price = $("#price").val(),
url = $("#url").val();
When you call .valueOf() on a jQuery object, it gets an array of DOM elements...and that doesn't serialize well :)
In your $.post call if you pass JSON as a 4th parameter then jQuery will expect VALID json string only other wise it might cause error.
example of valid JSON is
var json = {"a":"my name", "b":"my school"};