Closed esallum-iluminare closed 3 years ago
Hi @esallum-iluminare I'm happy to help :-) Thank you for your great feedback about the eBook.
1) When you are creating an endpoint for a concrete resource (like a user id) I would create an route patter like GET /users/{id}
.
Example URL: /users/123
$app->get('/users/{id}', \App\Action\User\UserReaderAction::class)
But when you have some kind of dynamic search inputs, a classic HTTP QueryString would be a better option because of the flexibility and because of some special chars that should not be in a URI path (for technical reasons).
Example URL: /users?firstname=Sally&lastname=Doe
$app->get('/users', \App\Action\User\UserFindAction::class)`
Then fetch the query parameters from the request object:
$params = $request->getQueryParams();
2) Yes, the validation belongs into the Service. Example
Do you have any complete examples on your blog or in the book that I can follow of QueryParams and also a route that uses the PATCH method?
Best practice here would be to follow the RESTful principles.
Are there any communication channels (Telegram, Discord) for book buyers?
Yes, for public questions you can use this GitHub issue page. I also have Discord, Skype, Teams. For private consultation, code reviews, training, etc... you can contact me here.
Thanks again Odan! My code looked like this:
//routes
$app->get('/users', \App\Action\User\UserFindAction::class);
//UserFindAction
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
$params = $request->getQueryParams();
// Optional: Pass parameters from the request to the findUsers method
$users = $this->userFinder->findUsers($params);
return $this->transform($response, $users);
}
//UserFinder
public function findUsers($params): array
{
$queryParams[] = [];
if (!empty($params)){
$queryParams = [
'search_string' => $params['search_string'],
'limit' => intval($params['limit']),
'offset' => intval($params['offset']),
];
}
return $this->repository->findUsers($queryParams);
}
//UserFinderRepository
public function findUsers($queryParams): array
{
$query = $this->queryFactory->newSelect('users');
$query->select(
[
'id',
'username',
'first_name',
'last_name',
'email',
'user_role_id',
'locale',
'enabled',
]
);
// Add more "use case specific" conditions to the query
if (!empty($queryParams)) {
$query->where([
'OR' => [
'username LIKE' => '%' . $queryParams['search_string'] . '%',
'first_name LIKE' => '%' . $queryParams['search_string'] . '%',
'last_name LIKE' => '%' . $queryParams['search_string'] . '%'
]
])->limit($queryParams['limit'])->offset($queryParams['offset']);
}
$rows = $query->execute()->fetchAll('assoc') ?: [];
// Convert to list of objects
return $this->hydrator->hydrate($rows, UserData::class);
}
Is there anything I can improve it?
Looks good. Just a tip. When you have some clearly defined parameters, it would be better to declare them directly. Example:
public function findUsers(string $search, int $offset, int $limit): array
{
$query = $this->queryFactory->newSelect('users');
$query->select(
[
'id',
'username',
'first_name',
'last_name',
'email',
'user_role_id',
'locale',
'enabled',
]
);
if ($search) {
$query->andWhere(
[
'OR' => [
'username LIKE' => '%' . $search . '%',
'first_name LIKE' => '%' . $search . '%',
'last_name LIKE' => '%' . $search . '%',
],
]
);
}
$query->limit($limit);
$query->offset($offset);
$rows = $query->execute()->fetchAll('assoc') ?: [];
// Convert to list of objects
return $this->hydrator->hydrate($rows, UserData::class);
}
Usage:
$search = $params['search_string'] ?? '';
$offset = $params['offset '] ?? 0;
$limit = $params['limit '] ?? 10;
return $this->repository->findUsers($search, $offset, $limit);
Thanks @odan !
Hi Odan! How are you? I want to implement in all GETs of my API the parameters Limit and Offset as optional. I have some questions regarding QueryParams: 1) Using good programming practices, I can implement Query Params in URI $app->get('/users[/{array}]', \App\Action\User\UserFindAction::class), for example, or the more correct way is to create another URI with another action (UserSearchAction, for example): $app->get('/users/search[/{array}]', \App\Action\User\UserFindAction::class) . 2) The validation of this array of parameters is done only in the Service?
Do you have any complete examples on your blog or in the book that I can follow of QueryParams and also a route that uses the PATCH method? I really appreciate your help, I'm a beginner programmer, but I want to do everything as correctly as possible.
PS: I bought your book and found it sensational, it surprised the expectations a lot. I looked for copper, but I found gold. Are there any communication channels (Telegram, Discord) for book buyers?