skip to Main Content

I have a controller method which calls an external API and returns the result.
ControllerY -> getDataFromExternalAPI()

I call this controller method two different times in my app, in two distinct ways

  1. a batch job via php artisan xxx which where the command calls a controller which then calls the controller in question
    Command->ControllerX->ControllerY(getDataFromExternalAPI)
  2. the frontend calls a api route which is linked to the controller-method
    APIRoute>ControllerY(getDataFromExternalAPI)

Within the method the very same code runs through in both cases, the external API gets called, the result is json_decoded to an array, which is minorly edited, and then returned with

$responseArray=json_decode($response,true);
// here I do something with the array, and then
return response()->json($responseArray);

Call 1 with php artisan Command gives me an Error:

   Method IlluminateHttpJsonResponse::json does not exist.

Call 2 via internal API works perfectly, no error is given, results are displayed.
I checked the logs with detailed output and in both cases the external API returns a valid results, with the same structure.

I am completely clueless at the moment, as it’s the same code, with the same "content" but two different results, the only difference I see at the moment is the way the method is called. Also I make other API Calls within the command with the same call external API logic, they do work fine.

Could it be an environemnt issue with php artisan? Still does not make sense, as other API endpoints run through fine, and so does the internal API call…

As mentioned: what could I be missing?

[2024-01-24 22:32:15] ERROR SeriesController->updateStatistics(173): BadMethodCallException: Method IlluminateHttpJsonResponse::json does not exist. in /Volumes/Data-Partition/PHPStorm/github/borealis/vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:112
Stack trace:
#0 /Volumes/Data-Partition/PHPStorm/github/borealis/app/Http/Controllers/SeriesController.php(166): IlluminateHttpJsonResponse->__call('json', Array)
#1 /Volumes/Data-Partition/PHPStorm/github/borealis/app/Console/Commands/UpdateDataCommand.php(46): AppHttpControllersSeriesController->updateStatistics(Object(IlluminateHttpRequest))
#2 /Volumes/Data-Partition/PHPStorm/github/borealis/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): AppConsoleCommandsUpdateDataCommand->handle()

EDIT: I could verify indeed that when calling response()->json within an artisan command for a strange reason response() produces a IlluminateHttpJSONResponse object instead of a IlluminateHttpResponse object, then it makes sense that there is no json method.
But I have no clue why.
Meanwhile I pass a bool param $calledFromCommand which returns the array instead of the json, and later converts it into json.

If anyone can explain me what happens under the hood, I’m more than welcome.

2

Answers


  1. Chosen as BEST ANSWER

    I could verify indeed that when calling response()->json within an artisan command

    (new TwelveDataController())->getCompanyStats($request, true);
    

    for a strange reason response() produces a IlluminateHttpJSONResponse object instead of a IlluminateHttpResponse object, and therefore the ->json method is not available.

    So apparently it does matter how one calls a Controller-method. and it kind of makes sense, that when calling a Controller-method via API a IlluminateHttpResponse is generated, compared to a direct method call where you likely want a JSONResponse without the http header.

    Nevertheless I am not sure if that's a good design, one method produces to different results-objects depending on how it is called. Having said that, my solving hack, with an added param passed only when called from a Command, does the same: One method returns two objects

    if ($callFromCommand){
        return $responseArray;
    } else {
        return response()->json($responseArray);
    }
    

  2. In my opinion, not only a Controller calling another Controller’s method is a bad practice, I think you should not instantiate a Controller and call its method from another file. In other words, Controllers should only take requests from a client and return responses to the client.

    I suggest you move the getDataFromExternalAPI() method to another non-Controller class and return the result as an object/array. Both the artisan command and ControllerY can then call the method directly. It should take care of similar issues as you can independently process the retrieved data separately, e.g. return it as a JSON response on ControllerY and do stuffs with the data in the Artisan command

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search