Loopback 4 add a custom put request with two parameters - loopbackjs

I am trying to make a put request on the url http://[::1]:3000/carts?filter[where][user_id]=5&filter[where][cart_id]=52 with two parameters respectively 'user_id' and 'user_id'. This is what I have tried .
#put('/carts?filter[where][user_id]={u_id}&filter[where][cart_id]={id}', {
responses: {
'204': {
description: 'Cart PUT success',
},
},
})
async replaceById2(
#param.path.number('u_id') u_id: number,
#param.path.number('id') id: number,
#requestBody() cart: Cart,
): Promise<void> {
await this.cartRepository.replaceById(id, cart);
}
I am passing two parameters from frontend to update data respectively 'user_id' and 'cart_id'.
updatecartItem (user_id,id,cart): Observable<any> {
return this.http.put(this.cart_url + 'carts?filter[where][user_id]=' + user_id +'&filter[where][cart_id]=' + id, cart, {observe : 'response'})
}
But I am getting 404 error as follows
statusCode: 404 name: "NotFoundError" message: "Endpoint "PUT /carts"
not found."
Can you please direct me in creating custom put request with more than one parameters

Related

Pass an ID from Ajax to a Django view

I have a Django view that accepts an ID and returns a Json Response. Now on Ajax, I want to call the django view with an ID.
Here is my AJAX:
$(document).ready(function () {
$("#button").click(function () {
var id = 25;
$.ajax({
type: "POST", # Added here. Now error message changed
url: "/account/check_id/"
data: {
id: id,
},
dataType: "json",
success: function (data) {
if (data.is_taken) {
alert("ID is available");
}
},
});
});
});
Additional Data:
url:
path('check_id/<int:id>/', hrViews.check_id, name='check_id'),
view:
def check_id(request, id, *args, **kwargs):
However, when I click on button, I get error message
GET http://localhost:8000/account/check_id/?id=25 404 (Not Found). The ?id= is causing the error. How to remove it?
EDIT
After adding type: "POST", got message
POST http://localhost:8000/account/check_id/
How to pass ID here?
Note. Based on w3schools, the data{} is used to pass information to server. So I think that I should pass my ID here. However, my url does not get the ID from data. Please correct me on this if my assumption is wrong.
So I made some changes and this is what worked for me.
$(document).ready(function () {
$("#hold").click(function () {
var id = 25;
$.ajax({
url: "/account/check_id/" + id,
dataType: "json",
success: function (data) {
if (data.is_taken) {
alert("ID is available");
}
},
});
});
});
Removed the type: "POST", then concatinate on URL with my ID. It works so I will go with this based on my use case.

React put method not updating the user from Django

I have a Django as backend and updating the user from postman is working fine. But when I update it via React Frontend, it replies with a success message just as in Postman, but the data was not updated.
This is the update function to update:
const updateData = (e) => {
e.preventDefault();
const csrftoken = getCookie("csrf");
const cookies = new Cookies();
const url = "http://localhost:8000/usercontrol/update";
setIsLoading(true);
fetch(url, {
method: "PUT",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Token " + cookies.get("token"),
"X-CSRFToken": csrftoken,
},
body: JSON.stringify({
email: userinfo.email,
username: userinfo.username,
first_name: userinfo.first_name,
last_name: userinfo.last_name,
}),
}).then((response) => console.log("THE RESPONSE: ", response.json()));
setIsLoading(false);
};
This is what it prints out in the console
Since I am partially following CodingWithMitch for Django user creation with rest framework is similar to his.
Furthermore, since there is no error outputting and is working fine in Postman, I have no idea what is wrong with it.

Writing to DynamoDB table using API Gateway and Lambda from a Web page

Part of the project, I want to write data entered into my web page from onto to a DynamoDB database, for this, I have written a Node.js code in AWS lambda to write items into a DynamoDB table. Created a web page form with more than one entries for users to fill required information and created an API Gateway to connect Lambda and HTML web page. Below are the codes for Lambda, API gateway, and HTML form. Please go through them.
Lambda My code:
exports.handler = function (e,ctx,callback) {
"use strict";
var params = {
Item : {
marchp : e.stepno,
Prev_step_no :e.prevstepno,
Next_step_no: e.nextstepno,
Inputdata : e.inputdata,
Acknowledgement: e.acknowledgement,
Condition: e.condition,
},
TableName : 'MARCHPevents'
};
API Gateway Body Mapping Templates:
{
"stepno": $input.json("$.stepno"),
"prevstepno": $input.json("$.prevstepno"),
"nextstepno": $input.json("$.nextstepno"),
"inputdata": $input.json("$.inputdata"),
"acknowledgement": $input.json("$.acknowledgement"),
"condition": $input.json("$.condition")
}
HTML Code pasing data to API gateway:
url:API_URL,
success: function(data){
$('#entries').html('');
data.Items.forEach(function(MARCHPreventsItem){
$('#entries').append('<p>' + MARCHPreventsItem.InputData + '</p>');
})
}
});
});
$('#submitButton').on('click', function () {
$.ajax({
type: 'POST',
url: API_URL,
data: JSON.stringify({ "stepno": $('#s1').val() }),
data: JSON.stringify({ "prevstepno": $('#p1').val() }),
data: JSON.stringify({ "nextstepno": $('#n1').val() }),
data: JSON.stringify({ "inputdata": $('#msg').val() }),
data: JSON.stringify({ "acknowledgement": $('#ack').val() }),
data: JSON.stringify({ "condition": $('#con').val() }),
contentType: "application/json",
success: function (data) {
location.reload();
}
});
return false;
});
If on passed one value from HTMLwebpage form to API gateway to passing to perfectly to Lambda which writing that one value to DynamoDB.
Problem Facing is passing more than one value from HTML web page form to API gateway this time it is having an invocation error at Lambda
Any Help?
Your JavaScript looks incorrect - you are overwriting the data parameter. You need to set the properties on the data object, i.e.
var obj = {
stepno : ${'#s1'}.val(),
prevstepno : ${'#s2'}.val(),
...
}
$.ajax({
type: 'POST',
url: API_URL,
data: obj,
contentType: "application/json",
success: function (data) {
location.reload();
}
});

Client Error: bad object in message: bson length doesn't match what we found

I'm having an issue POSTing data to a Node/Express API that leverages Mongoose and MongoDB. When attempting a bulk insert using this schema, data and handler:
// Mongoose schema
var NotificationSchema = new Schema({
uuid: {
type: String,
required: true,
index: true
},
message: {
type: String,
required: true
},
url: {
type: String,
required: true
}
});
// sample data
[
{
'uuid': '34e1ffef49ad4001bb9231c21bdb3be7',
'url': '/polls/4666386cb92348af93417e9abb9ce880/forecast/',
'message': '#btaylor has shared a poll with you'
},
{
'uuid': '42d6a9f4b3f5416b952452c26e01789a',
'url': '/polls/4666386cb92348af93417e9abb9ce880/forecast/',
'message': '#btaylor has shared a poll with you'
}
]
// route handler
Notification.prototype.bulkInsert = function(data, callback) {
NotificationSchema.collection.insert(data, function(error, documents) {
if (error) { return callback(error, null); }
if (documents.length == 0) { return callback(null, null); }
callback(null, documents);
});
};
I get this back when POSTed as x-www-form-urlencoded via Postman:
{ [MongoError: Client Error: bad object in message: bson length doesn't match what we found]
name: 'MongoError',
err: 'Client Error: bad object in message: bson length doesn\'t match what we found',
code: 10307,
n: 0,
connectionId: 125,
ok: 1 }
My Mocha tests posting the same data work just fine. What am I doing wrong?
[Update]
After further testing, it appears that the body of the request is being improperly parsed when posted from my Django web application using the requests library.
My post is constructed as:
requests.post(url, data=data)
where data is a Python dictionary:
{'data': [{'url': '/polls/4666386cb92348af93417e9abb9ce880/forecast/', 'message': '#btaylor has shared a poll with you', 'uuid': '34e1ffef49ad4001bb9231c21bdb3be7'}, {'url': '/polls/4666386cb92348af93417e9abb9ce880/forecast/', 'message': '#btaylor has shared a poll with you', 'uuid': '42d6a9f4b3f5416b952452c26e01789a'}]}
The data argument that the above route handler receives is populated from req.body.data. In my Express middleware, I am using the following body parsers:
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
however, logging the request body, as posted from Django/requests results in:
[ 'url', 'message', 'uuid', 'url', 'message', 'uuid' ]
why are the values being stripped out, along with the curly braces defining the objects? The content type of the post is being reported correctly as:
application/x-www-form-urlencoded
Anyone have any ideas? This works perfectly from Postman, btw.
Turns out there was one problem on the Python side and one on the Express side.
The list of objects that I was posting from Python needed to be converted to a JSON string before being set in the values posted:
# views.py
notifications = json.dumps([{"uuid": profile.uuid_str,
"message": message, "url": poll_forecast_url}
for profile in shared_with])
requests.post(url, data={'data': notifications})
Earlier in my question you'll notice that I indicated the tests from Postman were failing. That's because the value of req.body.data on the Express side was being received as a string when an encoding of x-www-form-urlencoded was set in the Postman options. To fix this, I added this line before the Notification.bulkInsert() function call:
var data = typeof(req.body.data) == 'string' ? JSON.parse(req.body.data) : req.body.data;
to properly convert the JSON string to an object before passing it to .bulkInsert()

How do I return specific http status codes from a remote method in loopback?

I would like to know if there is a way to returns a specific HTTP status code from within a remote method.
I can see that there is a callback function which we can pass an error object, but how do we define the HTTP status code?
If you wish to use an HTTP status code to notify of an error, you can pass an error in the remote methods callback method:
var error = new Error("New password and confirmation do not match");
error.status = 400;
return cb(error);
You can find more information about the error object here: Error object
If you wish to just alter the HTTP response status without using an error, you can use one of the two methods defined by either #danielrvt or #superkhau. To obtain the reference to the request object mentioned by #superkhau, in your method registration you can define an additional argument that will be passed to your remote method. See HTTP mapping of input arguments
Lets assume that you have a CoffeShop Model and you want to send status 404 if the item is not in your db.
CoffeeShop.getName = function(req, res, cb) {
var shopId = req.query.id;
CoffeeShop.findById(shopId, function(err, instance) {
if (instance && instance.name){
var response = instance.name;
cb(null, response);
}
else {
res.status(404);
cb(null);
}
});
}
CoffeeShop.remoteMethod(
'getName',
{
http: { path: '/getname', verb: 'get' },
accepts: [{arg: 'req', type: 'object', http: { source: 'req' }},
{ arg: 'res', type: 'object', http: { source: 'res' }}],
returns: { arg: 'name', type: 'string' }
}
);
When using an async remote method function, you need to let the async function throw any encountered errors, rather than trying to catch them and call return. By calling return you're telling LoopBack that it should respond as if it were successful.
Here's an example working structure.
AdminDashboard.login = async(body) => {
let username = body.username
let password = body.password
await isDomainAdmin(username, password)
}
AdminDashboard.remoteMethod(
'login',
{
http: {path: '/login', verb: 'put'},
consumes: ['application/json'],
produces: ['application/json'],
accepts: [
{arg: 'body', type: 'Credentials', http: {source: 'body'}}
]
}
)
Just make sure that any internal functions you call like isDomainAdmin are also either throwing their errors directly, or that you catch them and convert them to an error object like this:
{
statusCode: 401,
message: 'Unauthorized'
}
Where err.statusCode is the HTTP status code you want LoopBack to return.
You can return any status code just like you would in ExpressJS.
...
res.status(400).send('Bad Request');
...
See http://expressjs.com/api.html
In your remote method registration:
YourModel.remoteMethod('yourMethod', {
accepts: [
{arg: 'res', type: 'object', http:{source: 'res'}}
],
...
returns: {root: true, type: 'string'},
http: {path: '/:id/data', verb: 'get'}
});
If you just need to modify response status, just do:
ctx.res.status(400);
return cb(null);