Routing a REST API in groups with Slim - php

I'm building a rest api with slim 3 but I'm having some trouble understanding how to do the routing. I initially had the get method working correctly at api.com/v1/companies/get and api.com/v1/companies/get/id and post method at api.com/v1/companies/post, but I refactored so all the methods would be at api.com/v1/companies/id and after this refactoring I get a 405 error on post requests saying that only the get method exists.
So I did a little more researching; the amount of small, but breaking inconsistencies I've found in other slim 3 guides has been a bit annoying, but it looks like my solution is the map() function, only I have no idea how to use it, and even the official docs skip over the part I don't understand.
This is how the code looked after the refactor that broke it:
$app->group('/v1', function() use ($app) {
$app->group('/companies', function() use ($app) {
$app->get('/{code}', function($request, $response, $args) {...}
$app->get('', function($request, $response, $args) {...}
$app->post('', function($request, $response, $args) {...}
});
});
And my first attempts at using map():
$app->group('/v1', function() use ($app) {
$app->map(['GET', 'POST', 'PUT', 'DELETE'], '/companies/{code}', function($request, $response, $args) use ($app) {
//here's where I don't know what to do
if($request->isGet()) {
//What goes here? And I seem to be having problems accessing my parameters?
}
}
}

This code works for me:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
$app = new \Slim\App;
$app->group('/v1', function() {
$this->map(['GET', 'POST', 'PUT', 'DELETE'], '/companies/{code}', function($request, $response, $args) {
if($request->isGet()) {
$response->getBody()->write("it's GET");
}
if($request->isPost()) {
$response->getBody()->write("it's POST");
}
if($request->isPut()) {
$response->getBody()->write("it's PUT");
}
if($request->isDelete()) {
$response->getBody()->write("it's DELETE");
}
return $response;
});
});
$app->run();
Please don't use $app inside group. In docs you can see that $this inside group point to instance of 'Slim\App' already. Also check your .htaccess file if it's configured as described in Slim3 documentation.

Related

Understanding Slim 4 routing function

I am trying to learn slim framework and I am following the tutorial. What I would like is a detailed explanation of what the be low snippet of code is doing within the slim environment.
$app->get('/client/{name}'
The reason that I am asking is because in keep getting route not found. But I have yet to figure out why. The base route works. But when I added the twig and tried to route to that. It fails.
Now comes the code:
This part is in my webroot/public/index.php
<?php
use DI\Container;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
use Twig\Error\LoaderError;
require __DIR__ . '/../vendor/autoload.php';
$container = new Container;
$settings = require __DIR__ . '/../app/settings.php';
$settings($container);
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);
// Create Twig
$twigPath = __DIR__ . "/../templates";
$twig = '';
try {
$twig = Twig::create($twigPath, ['cache' => false]);
} catch (LoaderError $e) {
echo "Error " . $e->getMessage();
}
// Add Twig-View Middleware
$app->add(TwigMiddleware::create($app, $twig));
$routes = require __DIR__ . '/../app/routes.php';
$routes($app);
$app->run();
This part is in the routes.php:
<?php
use Slim\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
return function (App $app) {
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write("Hello world! Really?");
return $response;
});
$app->get('/client/{name}', function (Request $request, Response $response, $args) {
$view = Twig::fromRequest($request);
return $view->render($response, 'client_profiles.html', [
'name' => $args['name']
]);
})->setName('profile');
};
The first route works fine the second does not. According to what I am reading. It should work. https://www.slimframework.com/docs/v4/features/templates.html
I feel that if I knew what get is looking to do. I may be able to fix it and build a proper route.
When I dig into the $app->get which connects with the RouterCollecorProxy.php. There is the $pattern variable and $callable. The callable is the anonymous function that comes after the common in the
$app->get('/client/{name}', function <- this is the callable, right?
I see the map class which takes me to the createRoute which returns the $methods, $pattern, callable and a few other things.
I think the pattern is where my problem is.

Organize Slim 3 API routes logic into functions

I would like structure the API in order to separate both the routing organization from actions in separate files.
The current code does not return any errors, but the parameters are not collected correctly.
Is there a simple way to organize into functions without the need for classes, or __invoke?, the application does not require it.
public/index.php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
$app = new \Slim\App;
foreach (glob("../src/middleware/*.php") as $middleware) {
require $middleware;
}
require '../src/routes/routes.php';
$app->run();
src/routes/routes.php
$app->group('/v1', function () use ($app) {
$app->post('/register', 'registerParticipant');
});
src/middleware/registerParticipant.php
require '../lib/qrlib/vendor/qrlib.php';
function registerParticipant($request, $response, $args) {
// demo for testing
$foo= $request->post('foo');
echo "foo= ".$foo;
// more app logic
}
Replacing $foo= $request->post('foo'); with $foo= $request->getParam('foo'); did the trick.
src/middleware/registerParticipant.php
require '../lib/qrlib/vendor/qrlib.php';
function registerParticipant($request, $response, $args) {
// demo for testing
$foo= $request->getParam('foo');
echo "foo= ".$foo;
// more app logic
}

Route pattern in middleware Slim v3

How can I get route pattern inside middleware:
routes.php:
$app->get('/myroute/{id}', function($req, $res, $args) {
//DO STUFF HERE
})->add(new MyMiddle());
middle.php:
class MyMiddle {
public function __invoke($req, $res, $next) {
//DO STUFF
}
}
In routes.php I can get {id} with $args['id'], but how can I get it inside MyMiddle.php?
Thank you,
Cristian Molina
Enable the determineRouteBeforeAppMiddleware setting:
$config = ['settings' => [
'determineRouteBeforeAppMiddleware' => true,
'displayErrorDetails' => true,
]];
$app = new \Slim\App($config);
You can now access the Route object from the Request, using getAttribute() and, from the route, get at the arguments:
$app->add(function ($request, $response, $next) {
$id = $request->getAttribute('route')->getArgument('id');
return $next($request, $response);
});
I decided to included a Slim v2 example as that is what I was looking for when I came across this post. You can use $this->app->router()->getCurrentRoute()->getPattern() from the slim.before.dispatch callback hook to accomplish the same thing.

PHP Slim get current route group

I want to get current route group.
For example group1 from
$app->group('/group1', function () use ($app) {
$app->get("/a"...
$app->get("/b"...
$app->get("/c"...
...
I can get route pattern from current route. The question is - is there any special way to get current route group?
What about $this ? The code is taken from their website.
$app = new \Slim\App();
$app->group('/users/{id:[0-9]+}', function () {
$this->map(['GET', 'DELETE', 'PATCH', 'PUT'], '', function ($request, $response, $args) {
// Find, delete, patch or replace user identified by $args['id']
})->setName('user');
$this->get('/reset-password', function ($request, $response, $args) {
// Reset the password for user identified by $args['id']
})->setName('user-password-reset');
});

How do I use slim framework route get all .. but not include except string

How do I use slim framework route get all .. but not include except string get /login
$app->get('/.*?', function () use ($uri, $app) {
$app->redirect($uri['public'].'/login');
});
$app->get('/login', function () use ($uri, $app) {
echo 'login view';
});
...
$app->post('/login', function () use ($uri, $app) {
$user_controller = new controller\user_controller();
$user_controller_login = $user_controller->login($uri, $app);
});
Slim routes are processed in order, so if you define the /login route before the catch-all, it will work in that order:
$app->get('/login', function() use($app) { ... });
$app->post('/login', ...);
$app->get('/.*', function() use($app) { $app->redirect('/login'); });
Although, I don't usually see 'catch all' style routes. Usually, you'd use URL rewriting to pass to static files not served by routes, and if you're doing this to ensure the user has logged-in to each page, you are better off using Slim Middleware to handle that.
For instance, if you had an authenticate piece of middleware, it could check on each of your routes for a login session/cookie/whatever, and if not found redirect to the login page (also passing the current url so they could be redirected back after login).
$authenticate = function() {
$app = \Slim\Slim::getInstance();
return function() use($app) {
// check for auth here somehow
if (!isset($_SESSION['user'])) {
$app->redirect('/login');
}
};
}
// Use middleware on your defined routes
$app->get('/stuff', $authenticate, function() use($app) { ... });
...

Categories