I'm having trouble with "AXIOS PATCH" method - laravel

I am trying to update my database record using "axios patch" method.
This is my code:
editClient(client) {
let data = new FormData();
data.append("name", this.client.name);
data.append("email", this.client.email);
data.append("phone", this.client.phone);
data.append("_method", "PATCH");
axios
.post(`/api/clients/${client.id}`, data)
.then(res => {
resolve(res.data.client);
})
.catch(err => console.log(err.response.data));
},
I tried this code:
axios
.patch(`/api/clients/${client.id}`, {
name: this.client.name,
phone: this.client.phone,
email: this.client.email
})
.then(res => {
resolve(res.data.client);
})
.catch(err => console.log(err.response.data));
But it also dosn't work.
The error i get is
POST http://localhost:8000/api/clients/27 500 (Internal Server Error)
{message: "SQLSTATE[42S22]: Column not found: 1054 Unknown co…4 02:12:57"` = updated_at:"2019-05-24 02:12:57"})", exception: "Illuminate\Database\QueryException", file: "C:\xampp\htdocs\prs3\vendor\laravel\framework\src\Illuminate\Database\Connection.php", line: 664, trace: Array(60)}
exception: "Illuminate\Database\QueryException"
file: "C:\xampp\htdocs\prs3\vendor\laravel\framework\src\Illuminate\Database\Connection.php"
line: 664
message: "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'name:"2011"' in 'where clause'
And when I tried this code:
axios
.patch(`/api/clients/${client.id}`, {
data: this.client
})
.then(res => {
resolve(res.data.client);
})
.catch(err => console.log(err.response.data));
The error i get is
app.js:285 PATCH http://localhost:8000/api/clients/27 422 (Unprocessable Entity)
{message: "The given data was invalid.", errors: {…}}
errors:
email: ["The email field is required."]
name: ["The name field is required."]
phone: ["The phone field is required."]
__proto__: Object
message: "The given data was invalid."
Im new in axios and vue. Im trying to learn on how to build and CRUD api using axios.
I tried to find other ways and i can't find any.
This is my controller:
public function update(Client $client) {
$val = $client ? ','.$client : '';
$client->update($this->_val($val));
return back();
}
public function _val($val) {
return request()->validate([
'name' => ['required', 'min:2', 'unique:clients,name'.$val],
'email' => ['required', 'email', 'unique:clients,email'.$val],
'phone' => ['required', 'alpha_num'],
]);
}

Your axios post code is fine. It's working fine. The error you get in the post field is larvel error column not found.
I guess you made a typo in some column name while saving data or you entered unknown column by mistake which is not in the table.
Please provide laravel side code, so we can see where you facing an error.
By the way from your question => Your axios.post code is correct

Related

Cannot catch error in promise chaining Larave-vue2 SPA authentication

I try to authenticate in Laravel9 Sanctum a SPA using vue3 and vuex, not with the token authentification but with the SPA Authentication.
I am not very used to the javascript language, and even less to promise chaining.
The first thing I am trying is registration.
Here are my methods.
The backend registration method
public function register(Request $request)
{
$request->validate([
'name' => 'required|string',
'email' => 'required|email|string|unique:users,email',
'password' => [
'required',
'confirmed',
Password::min(8)->mixedCase()->numbers()->symbols()
]
]);
$user=User::create([
'name' => $request['name'],
'email' => $request['email'],
'password' => bcrypt($request['password'])
]);
return response (['user'=>$user]);
}
The frontend registration method in the register.vue
//is actually the register form's data
const user = {
name: "",
email: "",
password: "",
password_confirmation: "",
};
function register(ev) {
ev.preventDefault();
store
.dispatch("register", user)
.then((data) => {
console.log("data in vue");
console.log(data);
router.push({
name: "Login",
});
})
.catch((error) => {
if (error.response.status === 422) {
errors = error.response.data.errors;
}
});
}
the actions method in the store/index.js
actions: {
register({ commit }, form) {
console.log("in register of index");
axiosClient.get("/sanctum/csrf-cookie");
return axiosClient.post("/api/register", form).then(({ data }) => {
console.log("data dans index");
console.log(data);
return data;
});
},
...
The registration is working fine but when I try an already existing email in the registration form, I get a status 422 as expected and this response from the axiosClient.post('/api/register',form):
{"message":"The email has already been
taken.","errors":{"email":["The email has already been taken."]}}
I expect this error to be intercepted by the catch in the register view but it doesn't happen. Despite this error I continue to use the .then and to push the Login route which is not what I want.
Can somebody tell me where I am doing wrong ?
I completely forget that in my axios.js there were interceptors that triggered this wrong behavior.
All is clear now.

axios post to find out if data is valid

OK I am at the end of my day and I am not thinking straight. So this is what I have...
a Laravel controller, send it a username, and it tells me if the username is available, and if it isnt, it gives me a 422 code
public function checkUsername(Request $request) {
Validator::make($request->all(), [
'name' => ['required', 'string', 'max:255', 'unique:users'],
])->validate();
return response()->json([
'valid' => true,
'data' => [
'message' => 'Username is available!'
]
], 200);
}
Example of valid response:
{"valid":true,"data":{"message":"Username is available!"}}%
The curl to test is:
curl -X POST -H "Content-Type: application/json" -d '{"name": "bossryan"}' http://127.0.0.1:8000/api/checkusername
Next: I have a frontend Vue using Vee-validate. It does a bunch of things, but I need to add this latest validation into the mix, so if the username is taken (I don't get the valid response from above, it needs to reply with "This username is already taken"
validateUsername(value) {
// if the field is empty
if (!value) {
return 'This field is required';
}
const regex = /^[a-zA-Z0-9_.+-]{4,20}$/i;
if (!regex.test(value)) {
return 'This must be a minimum of 4 characters';
}
return true;
},
This is the axios I created but it isnt working:
const isUnique = (value) => {
return axios.post('/api/checkusername', { email: value }).then((response) => {
// Notice that we return an object containing both a valid property and a data property.
return {
valid: response.data.valid,
data: {
message: response.data.message
}
};
});
};
I know I need to add in axios, but I am just having a heck of a time setting it up and my mind keeps rushing around. I am just looking for someone who can just help me plug in the axios request above //All is good, so I can finish this up.
THANKS FOR THE HELP COMMUNITY!
Vee-validate seems to want a resolved promise for async validation. Axios will reject the promise if the status is >= 400 so you need to handle that accordingly.
Assuming when validation fails that the response body matches the same { valid, data: { message } } format, you'd want something like the following
const isUnique = (name) =>
axios.post("/api/checkusername", { name })
.then(({ data }) => data)
.catch(err => ({ // resolve with error details
valid: err.response?.data?.valid ?? false,
data: {
// get the message from the response if it exists
message: err.response?.data?.data?.message ?? "Validation failed"
}
}));
export default {
methods: {
async validateUsername(value) {
// do your synchronous checks as per question
const check = await isUnique(value);
return check.valid || check.data.message;
}
}
}
This will provide a generic message "Validation failed" if the 422 response body doesn't match expectations.

Paypal API Subscription Create returns 400 Bad Request response "name", though request is formed as in documentation

I try to implement Paypal subscription service according to: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
This is my first try.
In sandbox business account I have created two test subscriptions: monthly and yearly and configured application with their id's.
This is the method:
public function createSubscription($planSlug, $name, $email) {
return $this->makeRequest(
'POST',
'v1/billing/subscriptions',
[],
[
'plan_id' => $this->plans[$planSlug],
'subscriber' => [
'name' => [
'given_name' => $name,
],
'email_address' => $email
],
'application_context'=> [
'brand_name' => config('app.name'),
'shipping_preference' => 'NO_SHIPPING',
'user_action' => 'SUBSCRIBE_NOW',
'return_url' => route('subscribe.approval', ['plan' => $planSlug]),
'cancel_url'=> route('subscribe.cancelled')
],
],
[],
$isJsonRequest = true
);
}
However, when I make a call to API, to create a test subscription, I get weird response that 'name' parameter is formed incorrectly:
php artisan tinker
>>> $paypal = resolve(App\Services\PaypalService::class);
=> App\Services\PaypalService {#3413}
>>> $paypal->createSubscription('monthly', 'Test', 'test#test.com');
GuzzleHttp\Exception\ClientException with message 'Client error: `POST https://api-
m.sandbox.paypal.com/v1/billing/subscriptions` resulted in a `400 Bad Request` response:
{"name":"INVALID_REQUEST","message":"Request is not well-formed, syntactically incorrect, or
violates schema.","debug_id (truncated...)
This is strange, because in Paypal API doc (see above), the 'name' param is described exactly like that!
Do I miss something or it is Paypal API is acting funky?
try this :
try {
// your code here
} catch(\Throwable $th) {
if ($th instanceof ClientException) {
$r = $th->getResponse();
$responseBodyAsString = json_decode($r->getBody()->getContents());
dd($responseBodyAsString);
}
}
I've faced this too before and it was not easy for me to figure out how to show an explicit error message.
'return_url' => route('subscribe.approval', ['plan' => $planSlug]),
'cancel_url'=> route('subscribe.cancelled')
the problem is in this two url, may be you have changed the APP_URL in the .env
APP_URL=http://127.0.0.1:8000
put app url that and try

PayPalRestSDK: Mock Response Instrument_Declined response when capturing order

I've been struggling to mock the 'INSTRUMENT_DECLINED' issue, which according to Paypal is an usual error after attempting to capture an order (https://developer.paypal.com/demo/checkout/#/pattern/server).
Correctly setting the header to mock the response will help me to simulate other errors from the docs https://developer.paypal.com/docs/business/test-and-go-live/simulation-tests/#orders.
I'm using Laravel back end and React front end.
I have already gotten the expected mocked response using axios and calling in the front-end:
return axios
.post(
`https://api-m.sandbox.paypal.com/v2/checkout/orders/${orderID}/capture`,
{},
{
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + accessToken,
"PayPal-Mock-Response":
'{"mock_application_codes":"INSTRUMENT_DECLINED"}',
},
}
)
.then((res) => {
console.log(res);
})
However, I don't want to expose accessToken into the front end, I'd prefer to do everything in the back-end with GuzzleHtttp.
I've already had a positive response - with 'status': 'COMPLETED' without adding PayPal-Mock-Response header like so:
$client = new \GuzzleHttp\Client();
$response = $client->request(
'POST',
'https://api-m.sandbox.paypal.com/v2/checkout/orders/' . $paypalOrderId . '/capture',
[
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $access_token,
// 'PayPal-Mock-Response' => json_encode(["mock_application_codes" => "INSTRUMENT_DECLINED"]),
// 'PayPal-Mock-Response' => "['mock_application_codes':'INSTRUMENT_DECLINED]",
],
],
);
$data = json_decode($response->getBody(), true);
But when adding the PayPal-Mock-Response header like shown in the commented code from above, both attemps have returned this exception:
"message": "Client error: POST https://api-m.sandbox.paypal.com/v2/checkout/orders/9HG50866FU785784C/capture
resulted in a 404 Not Found response",
"exception": "GuzzleHttp\Exception\ClientException",
"file": "C:\xampp\htdocs\react\React-Laravel\vinos-gdl\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php",
This exception, I'm sure has to do to the way I'm passing the PayPal-Mock-Response header into the Guzzle http call but I can't find the way to do it correctly.
Any help is much appreciated.
UPDATE SOLVED**
Ok the way to go is sending the header like so:
'PayPal-Mock-Response' => json_encode(["mock_application_codes" => "INSTRUMENT_DECLINED"]),
I dunno if I had any typo but I finally got it. I also used INTERNAL_SERVER_ERROR to get a 500 response from server and built a catch for every situation:
} catch (ClientException $e) {
if ($e->hasResponse()) {
return response()->json([
'msg' => 'Client Exception',
'error' => json_decode($e->getResponse()->getBody()),
], 400);
}
return response()->json([
'msg' => 'Client Exception',
'request' => $e->getRequest(),
$e->hasResponse() ? $e->getResponse() : ""
]);
// return response()->json(['msg' => 'Server Error', 'error' => report($e)]);
} catch (BadResponseException $e) {
if ($e->hasResponse()) {
return response()->json([
'msg' => 'Uknown Exception',
'error' => json_decode($e->getResponse()->getBody()),
], 500);
}
return response()->json([
'msg' => 'Uknown Exception',
'request' => $e->getRequest(),
$e->hasResponse() ? $e->getResponse() : ""
]);
}
Thanks for the ones who commented.
"PayPal-Mock-Response":
'{"mock_application_codes":"INSTRUMENT_DECLINED"}',
...
// 'PayPal-Mock-Response' => "['mock_application_codes':'INSTRUMENT_DECLINED]",
There is a difference betwen {} (JSON object) and [] (JSON array).
What you have inside the brackets is not an array, so its syntax is invalid. It doesn't map to anything PayPal expects, hence the 404.

Laravel request validation - nullable image

I have registration form with username, email, password and avatar(image) fields. Everything works except image filed, which can be null. I am using Vue as front-end and send data with axios to Laravel.
This is validation:
public function register(Request $request)
{
$request->validate([
'username' => 'required|string|max:255|unique:users',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
'avatar' => 'nullable|image|mimes:jpg,jpeg,png|max:1999'
]);
$fileNameToStore = 'noimage.jpg';
return User::create([
'username' => $request->username,
'email' => $request->email,
'password' => Hash::make($request->password),
'avatar' => $fileNameToStore
]);
}
And this is how I send data:
register(context, data) {
let formData = new FormData();
formData.append('avatar', data.avatar)
formData.append('username', data.username)
formData.append('email', data.email)
formData.append('password', data.password)
return new Promise((resolve, reject) => {
axios.post('/register', formData,{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
}
If I fill out every filed it works fine and also other things like checking extension or file size works, only problem is when I don't select any image. I have nullable included in validation, but I still get error message from validation that it must be an image and which extension it needs to have.
If your data.avatar is undefined or null, your server will eiter receive a undefined or null string as a value for your avatar field. Therefore, Laravel will be testing the image rule on the string.
To fix it, you can make sure your image is not undefined to send it in your request.
if (data.avatar) {
formData.append('avatar', data.avatar);
}
Or
formData.append('avatar', data.avatar ? data.avatar : '');
this is because of data.avatar send to backend as an empty string and
you can write a watch for data.avatar, which every time data.avatar is empty string change it to null . like the following code :
watch(){
'data.avatar'(value){
if(value == '' || value == undefined){
this.data.avatar = null
}
}
}
This is how I did mine and it worked for me very well, I just added a ref attribute on the input that should be the user avatar and then retrieved the value of the input through Vue as follows this.$refs.photo.files[0]:
In my HTML using Vue
<input id="image" class="opacity-0" type="file" ref="photo">
and in my js using Vue
var data = new formData();
if(this.$refs.photo.files.length > 0)
data.append('photo', this.$refs.photo.files[0]);
axios.post(...).then(...);

Resources