I am trying to create a subscribe method for my laravel app that uses the mailchimp api to subscribe a user to a given list. The method works fine when the email address is not already on the lsit. when it is already subscribed the mailchimp api throws the following error
Mailchimp_List_AlreadySubscribed blah#blah.co is already subscribed to
list Tc App Test List. Click here to update your profile.
with the following code being shown
public function castError($result) {
if($result['status'] !== 'error' || !$result['name']) throw new Mailchimp_Error('We received an unexpected error: ' . json_encode($result));
$class = (isset(self::$error_map[$result['name']])) ? self::$error_map[$result['name']] : 'Mailchimp_Error';
return new $class($result['error'], $result['code']);
}
I have attempted a try catch block to catch the error but it is still being returned to the browser, here is what I tried and were it says MailChimp_Error I tried with Exception as well.
public function subscribe($id, $email, $merge_vars)
{
try {
$this->mailchimp->lists->subscribe($id, $email, $merge_vars);
} catch (MailChimp_Error $e) {
$response = 'an error has occured';
}
return $response;
}
Ultimately I want to be able to run the method and then either return either a success message or a message describing the issue to the user. the 3 possible mailchimp method errors are Email_notexists, list_alreadysubscribed and list does not exist although tihs last one should not occur as I am providing the list in the source code.
edit 1; after being in touch with mailchimp api support they suggested this code but the error still gets returned to the browser in its entirety
try {
$results = $this->mailchimp->lists->subscribe($id, $email, $merge_vars);
} catch (Mailchimp_Error $e) {
if ($e->getMessage()) {
$error = 'Code:'.$e->getCode().': '.$e->getMessage();
}
}
echo $error;
You can do
try
{
$response = $this->mailchimp->lists->addListMember($list_id, [
"email_address" => $email,
"status" => "subscribed",
]);
}
catch (\EXCEPTION $e) {
return $e->getMessage();
}
The \EXCEPTION handles a sort of error for stripe
Subscribe is in a namespace Acme\Emails\Subscribe so catch(Mailchimp_Error $e) looks for Mailchimp_Error in this namespace.
Changing it to catch(\Mailchimp_Error $e) makes it look in the root namespace and then it works as intended
Related
I'm trying to use Laravel API Resource and handle the error message by sending a specific HTTP code
Here is my code :
public function show($id)
{
try {
return FruitResource::make(Fruit::find($id));
}
catch(Exception $e)
{
throw new HttpException(500, 'My custom error message');
}
}
My try/catch is systematically ignored when I try to access the route.
I am voluntarily accessing an object that is not in the database. I have ErrorException with message Trying to get property 'id' of non-object.
I would like to be able to send my own Exception here, in case the user tries to access data that doesn't exist. And return a json error.
Try this (notice the \ before Exception):
public function show($id)
{
try {
return FruitResource::make(Fruit::find($id));
}
catch(\Exception $e)
{
throw new HttpException(500, 'My custom error message');
}
}
I have a custom class with function, which calls a function of the Yii2 core BasisAuthentication. In the core module is defined, if the credentials are not valid,
throw new UnauthorizedHttpException('Your request was made with invalid credentials.');
With this, the whole request is ended. But I need to go further (because it is a REST request).
I've tried to prevent from that with
try {
$identity = $basic_Auth->authenticate($user, $request, null );
} catch (Exception $e) {
return null;
}
But this is not working. I don't want to adapt the core files of Yii. What can I do?
try {
$identity = $basic_Auth->authenticate($user, $request, null );
} catch (\Throwable $e) {
return null;
}
I'm trying to customize error messages.
For handling errors i used "try/catch" block according to this Recurly documentation, like this for example:
try {
$account = Recurly_Account::get('my_account_id');
$subscription = new Recurly_Subscription();
$subscription->account = $account;
$subscription->plan_code = 'my_plan_code';
$subscription->coupon_code = 'my_coupon_code';
/* .. etc .. */
$subscription->create();
}
catch (Exception $e) {
$errorMsg = $e->getMessage();
print $errorMsg;
}
I wanted use code in catch block like this:
catch (Exception $e) {
$errorCode = $e->getCode();
print $myErrorMsg[$errorCode]; // array of my custom messages.
}
But getCode() method always returns zero for all possible errors.
My question for Recurly Team (or who there in this theme):
How i get error code for errors? Or please explain me how i can resolve this topic. Thanks!
If you look at the PHP Client on Github and you search for "throw new" which is what is done when an exception is thrown you'll see that they don't set the exception error code the second parameter of the exception constructor method.
Recurly PHP Client on Github: https://github.com/recurly/recurly-client-php/search?utf8=%E2%9C%93&q=throw+new
PHP Exception documentation: http://php.net/manual/en/language.exceptions.extending.php
Therefore, you'll either need to catch more exceptions based on their name
i.e.
catch (Recurly_NotFoundError $e) {
print 'Record could not be found';
}
OR
look at the exception message and compare it
catch (Exception $e) {
$errorMessage = $e->getMessage();
if($errorMessage=='Coupon is not redeemable.')
{
$myerrorCode=1;
}
//Add more else if, or case switch statement to handle the various errors you want to handle
print $myErrorMsg[$myerrorCode]; // array of my custom messages.
}
I want to know which is the way to implement error in RestAPI, actually if a method in my classes generate an exception I return this ...
if(mysqli_connect_errno()) {
throw new Exception("Can't connect to db.");
}
... but this is a bad practice 'cause an API should be return a json.
So my idea is create a class called Errors and, in each class, when an error is fired I simply call the relative error number for display the json error.
Someone have another idea?
Maybe something like so :
<?php
try {
// Do your stuff
if(mysqli_connect_errno()) {
throw new Exception("Can't connect to db.");
}
} catch (Exception $e) {
echo json_encode(array("success" => false, "message" => $e->getMessage()));
return;
}
I think #Gwendal answer is good but it's no enough just to return a json response, you also have to return the proper http code:
<?php
try {
// Do your stuff
} catch (Exception $e) {
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
echo json_encode(array("success" => false, "message" => $e->getMessage()));
return;
}
I think you're in the right path. There are a couple of concerns that you're dealing with in here. First one is error handling, whilst the second one is error formatting.
Error handling can be done in several ways, and throwing exceptions is one of them. In order to find out when something bad happened, you'll need to wrap your exceptions within a try/catch block:
try {
//logic
if(mysqli_connect_errno()) {
throw new Exception("Can't connect to db.");
}
//more logic
} catch (Exception $e) {
//handle the error here
}
If you're following this route, I'd suggest you to be more specific in your exceptions, so you can better build your responses in your API. It's not the same having the DB down than to not being able to find a resource, for instance:
try {
//logic
if(mysqli_connect_errno()) {
throw new DBException("Can't connect to db.");
}
if(is_null($entity)) {
throw new ResourceNotFoundException("Entity could not be found");
}
//more logic
} catch (DBException $e) {
//handle DB error here
} catch (ResourceNotFoundException $e) {
//handle resource not found error here
}
Now for the formatting part, the normal response in REST APIs are JSON responses. One way to go about it, would be to create a specific class whose sole responsibility would be to transforms your response into a valid JSON:
...
} catch (DBException $e) {
return $this->JSONResponse->format("Sorry we could not complete your request", 500);
} catch (ResourceNotFoundException $e) {
return $this->JSONResponse->format("The resource you were looking for could not be found", 404);
}
As you can see, different errors have different status codes. The implementation of the class is quite trivial:
class JSONResponse {
public function format($message, $statusCode) {
return json_encode(['message' => $message, 'code' => $statusCode]);
}
}
This does not change the status code of the response though, which is essential to good REST API design. You'll need to set the appropriate status code by using this function.
You can find a more robust and flexible implementation of this class in the Symfony HTTPFoundation Component, which extends from the normal Response class.
My RESTful API always returns a JSON of this structure:
[
'resource' : [],
'code' : [
'id' : int,
'msg' : string
],
'meta' : [],
'log' : []
]
If I return data, the data is always in resource and code['id'] is always 0 (which represents 'OK'). When an error occours, I return an empty resource and some error code. Also I provide some extra information via meta and can log some actions via log which helps me a lot with debugging.
This might also help you with future issues, for example if you want to split an answer into pages so the client should request data via GET /path/to/resource/page/:page or want to notice the client that a certain request path is deprecated.
I have made a simple PHP script which uploads a file to Google Drive. I then run the following function:
function PublishToWeb($service, $fileId, $revisionId) {
$patchedRevision = new Google_Revision();
$patchedRevision->setPublished(true);
$patchedRevision->setPublishAuto(true);
$patchedRevision->setPublishedOutsideDomain(true);
try {
return $service->revisions->patch($fileId, $revisionId, $patchedRevision);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
I get no error message but the word document is not published.
When I try to set the flags using the Google APIs explorer it returns no errors but also fails to set the published flag to true. Am I missing something obvious?
For clarity I'm trying to upload a file then instantly simulate pressing 'Publish to web'. I also tried using revisions.update
Update:
Okay, I've figured out that the document has to be uploaded and converted to a google doc format to be published. However when the document is saved as a google doc it has no headrevisionid set so I can't use revisions.update or revisions.patch
Anyone know how to publish a google doc file?
Okay I figured it out.
When uploading the file convert to a google doc
$createdFile = $service->files->insert($file, array(
'data' => $data,
'convert' => 'true',
));
Then update the published flag to true
$revisionId = 1; //The revisionId for a newly created google doc will = 1
function updateRevision($service, $fileId, $revisionId) {
$patchedRevision = new Google_Revision();
$patchedRevision->setPublished(true);
$patchedRevision->setPublishAuto(true);
$patchedRevision->setPublishedOutsideDomain(true);
try {
return $service->revisions->patch($fileId, $revisionId, $patchedRevision);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
Then build the publishedlink as this isn't done for you
$PublishURL = 'https://docs.google.com/document/d/'.$fileId.'/pub';