Consuming API internally

If I was to use Slim to write a REST Api but wanted to use it internally, what’s the best way? I’ve read people suggest subRequest when questions are asked about internally consuming APIs, but what if I didn’t want to make an HTTP request to Slim?

Would something like the following work: setting up a mock environment with \Slim\Http\Environment::mock to create an environment then use that for the request, then pass this to the App constructor, call run in silent mode can work with the response from that.

Maybe there’s a better/more accepted way?


What are the reasons for creating an internal REST API instead of a implementation of an interface in PHP?

If you are looking for a way to call an API both directly from PHP and make it available through a REST API, you could look into creating a service layer. The service layer can be called directly, for the REST API you could use Slim and call the service layer in the controllers.

I think your idea makes a lot of sense - and I probably showed my naivety on this topic as I’m learning as I go.

Indeed I want to internally use the API from PHP but also offer it over a REST API. My thinking was to make the internal work as much like REST as possible, so in the end there would be a helper class which did all the work I originally mentioned, and then your usage of said class would be something like:

$api = new ApiHelper();
$myBook = $api->callRoute('GET', '/books/123');
echo "{$myBook->title}\n";
$newBookmark = $api->callRoute('POST', '/bookmarks', ['id' => $myBook->id]);
echo "Bookmarked successfully ( {$newBookmark->reference})\n";

Developers would easily figure out what to pass to callRoute by looking at the rest documentation and the two would be very similar.

Do you think using slim ONLY for REST is best practice, where routes would simply call class methods internally the same way as other normal PHP integrations would?

Regardless, I find it quite interesting in terms of learning – if it’s possible and what drawbacks it has as opposed to a service layer – so may I will try knock up some working code anyway for the fun of it.

Calling it a best practice would mean ruling out other viable solutions, so I would rather call it a good practice :). Adding a service layer separates concerns, but also adds to code complexity, so I wouldn’t introduce where it can be avoided.

Slim’s subRequest won’t make a HTTP request. It will mock a request and get the response for it. See the code here.

P.S: App level middleware won’t be executed with subRequest. Only the route level middleware.

You need to write your code in a more abstracted way.

Instead of shoving your business logic in your route action, you place it into a service class that accepts values in the method.


$app->post('/auth', function ($req, $res, $args) {
    $user = User::findByUsername($req->getParsedBody()['username']);

Instead you create a Service Provider


$userProvider->validateUser($username, $password);

Then you do…

$app->post('/auth', function ($req, $res, $args) {
    $result = $userProvider->validateUser($req->getParsedBody()['username'], $req->getParsedBody()['password']);

This then enables you to call the php $userProvider->validateUser anywhere else in your system without the need of mocking Http objects.

1 Like