Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.0][webservice] API pagination links #27005

Merged
merged 19 commits into from
Apr 4, 2020
Merged

Conversation

stefanoel
Copy link
Contributor

Pull Request for Issue #27004 .

Summary of Changes

\libraries\src\MVC\View\JsonApiView.php was modified adding model->setState because 'start' and 'limit' weren't populated and they always got default values (0 and 20) showing the first 20 records.
I don't know if there's a better solution than this one to achieve the same result...
Furthermore, I've added checks to omit unnecessary pagination links.

com_config APIs now return correct links.

I'm not sure about the best way/place to encode square brackets...

Testing Instructions

\libraries\src\MVC\View\JsonApiView.php

/api/index.php/v1/plugins
/api/index.php/v1/plugins?page[offset]=10&page[limit]=10 (a generic page)
/api/index.php/v1/plugins?page[offset]=110&page[limit]=10 (last page)

\api\components\com_config\View\Application\JsonapiView.php

/api/index.php/v1/config/application

\api\components\com_config\View\Component\JsonapiView.php

/api/index.php/v1/config/com_content
/api/index.php/v1/config/com_content?page[offset]=40&page[limit]=20 (a generic page)
/api/index.php/v1/config/com_content?page[offset]=60&page[limit]=20 (last page)

Expected result

Actual result

Documentation Changes Required

API com_config now return correct links for pagination.
Similarly, fixed JsonApiView.php.
In JsonApiView I added model->setState because 'start' and 'limit' weren't populated and they always got default values (0 and 20) showing the first 20 records.
I don't know if there's a better solution than this one...
@brianteeman
Copy link
Contributor

From what is described this PR does exactly what it says. I dont know enough to determine if it is correct to remove the unnecessary pagination links but it does what it says

$currentPageQuery = $currentUrl->getVar('page', $currentPageDefaultInformation);

// Set model start and limit params
$model->setState('list.start', $currentPageQuery['offset']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understood what you mean...
I moved $model->setState from JsonApiView.php to ApiController.php, using values obtained from the input page param (https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/MVC/Controller/ApiController.php#L201), and it seems to work fine.
So, can I commit these changes?
But in that case, I'd like to ask some clarifications on how the pagination params are stored in $this->input

$internalPaginationMapping = [];
if (\array_key_exists('offset', $paginationInfo))
{
$this->input->set('limitstart', $paginationInfo['offset']);
}
if (\array_key_exists('limit', $paginationInfo))
{
$internalPaginationMapping['limit'] = $paginationInfo['limit'];
}
$this->input->set('list', $internalPaginationMapping);

Here is used an array ($internalPaginationMapping) to store only the limit param, and moreover, dumping $this->input I noticed that the array isn't stored as associative, 'limit' key is dropped. Could these line be reviewed or this way of store pagination params in input are mandatory?

@wilsonge
Copy link
Contributor

wilsonge commented Nov 6, 2019

I dont know enough to determine if it is correct to remove the unnecessary pagination links but it does what it says

JSON API as a spec doesn't have strong opinions https://jsonapi.org/format/#fetching-pagination it just says "Keys MUST either be omitted or have a null value to indicate that a particular link is unavailable.". My feeling is first/last as a link is available so should be present (even if it's the current page). But I would definitely agree that having previous/next as nullable makes sense. As with all these subjective things - it's always down to personal preference :)

@brianteeman
Copy link
Contributor

My feeling is first/last as a link is available so should be present (even if it's the current page)

In the gui they would be disabled

@noccioletta
Copy link

Hi, I'd like to better understand your responses:
is the workaround proposed by @stefanoel consistent or not ?
Is it worthwhile for Joomla4 ?

@wilsonge
Copy link
Contributor

wilsonge commented Nov 7, 2019

The changes to next/previous page is a good change. I think the first/last links should always be present.
I also think the view shouldn't be setting state into the model - it should be handled in the controller already.

@chrisdavenport
Copy link
Contributor

The question of whether to include first/last/next/previous links on pages where they are redundant is one I've thought about before. As a rule of thumb I prefer to avoid them. My reasoning is that links are pointers to possible state transitions (that's what HATEOAS is all about), but redundant links are a bit like empty promises; it looks like they should lead to a state transition but actually they just lead straight back to the current state.

The client needs to know definitively that it has reached the first/last page when paginating. Including redundant links means that the client must compare the current URI with the first/last link URI and decide if they're the same or not. This can sometimes be tricky if the request URI can include arguments that don't affect the result set: how does the client know to ignore them when URI structure is supposed to be opaque? A simple string comparison may not suffice; it must reduce both to a canonical form before the comparison. It's only really safe to include redundant links if there are other signals that the client can use to decide whether it needs to follow a link or not. For example, if there are separate pageNumber and pageCount attributes returned in the response.

So, in my opinion, if you include redundant links, you should also include pageNumber and pageCount (or something similar) and encourage developers not to do URI comparisons. On the other hand, omitting redundant links doesn't mean that you should omit pageNumber/pageCount as they can be used by clients that want to randomly access pages.

So my preference is to omit redundant links but include pageNumber/pageCount (or better still something like Offset and totalCount as the concept of a page can be a bit problematic). And on a first pass at least, assume that the data is essentially static so you don't have to worry about insertions and deletions accidentally resulting in duplications and omissions when paginating; that's a whole other problem to solve.

@wilsonge
Copy link
Contributor

wilsonge commented Nov 7, 2019

There already is a total-pages property available.

The client needs to know definitively that it has reached the first/last page when paginating

That's why you use the next/previous attributes for in JSON API

This can sometimes be tricky if the request URI can include arguments that don't affect the result set

These are always going to be query parameters. If the URL path is physically different you cannot guarantee the data is the same (and in our core Joomla response this is the case anyhow for the purposes of said checks - which is the more concrete thing - because ultimately people are parsing our responses).

I don't see first and last pages are not necessarily redundant even if they are the same page. Previous/Next definitely would be redundant because it's not actually a next/previous page if they don't exist

Removed $model->setState from the view, everything seems to work...
ToDo: square brackets encoding?
I introduced the method "queryEncode" to encode square brackets in pagination links.
AbstractURI->toString() returns unencoded brackets, so I had to find a workaround, but I'm not sure it's the cleanest way to do this.
The method is defined as protected in Joomla\CMS\MVC\View\JsonApiView so that it can be used by other extending classes, like com_config api views.
Fixed an error in com_config component view pagination (L109).
@stefanoel
Copy link
Contributor Author

About square brackets encoding

Pagination links have unencoded square brackets, due to AbstractURI buildQuery method (https://github.com/joomla-framework/uri/blob/eed89d4997fcc52c08bba56116fa3ac4aef6a9db/src/AbstractUri.php#L345-L348) as it was already reported here

so, to comply with JSON API spec, I chose to handle the encoding with an ad hoc protected method (I've also updated the com_config APIs to use it)
https://github.com/stefanoel/joomla-cms-wstest/blob/5df64298d7445ba3183923b00e65bcf5df434e1e/libraries/src/MVC/View/JsonApiView.php#L265

Now the links returned have encoded square brackets.
Any suggestions?

@alikon alikon added the GSoC label Jan 15, 2020
@Ankit7Das
Copy link

I wish to work on it

@alikon alikon removed the GSoC label Feb 23, 2020
@wilsonge
Copy link
Contributor

@stefanoel apologies this one dropped off my radar. are you willing to fix the conflicts here so i can do a round of testing and get it in please

Co-Authored-By: Quy <quy@fluxbb.org>
@stefanoel stefanoel closed this Mar 20, 2020
@stefanoel stefanoel reopened this Mar 20, 2020
@stefanoel
Copy link
Contributor Author

sorry, now I'm stuck and I can't undestand the problem... I can't access my workstation and I'm not used to solve things from web interface... can you help please?

@Razzo1987
Copy link
Contributor

I have not tested this item.

When I try to apply the patch (Joomla! Patch Tester 3.0.0 beta 4):

Error
The file marked for modification does not exist: api/components/com_config/View/Application/JsonapiView.php


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/27005.

@alikon
Copy link
Contributor

alikon commented Mar 23, 2020

can i suggest you to use git commands to apply this patch
curl -L https://github.com/joomla/joomla-cms/pull/27005.diff | git apply

patchtester > Patch Tester 3.0.0 Beta 3 is still a WIP

anyway this pr needs conflict to be solved

@alikon
Copy link
Contributor

alikon commented Mar 23, 2020

@stefanoel can you fix conflict please

@stefanoel
Copy link
Contributor Author

can i suggest you to use git commands to apply this patch
curl -L https://github.com/joomla/joomla-cms/pull/27005.diff | git apply

patchtester > Patch Tester 3.0.0 Beta 3 is still a WIP

anyway this pr needs conflict to be solved

Hi @alikon can you suggest how to do it from web interface? I'm working from home due to coronavirus emergency here in Italy, and I have to use a smartphone these days. I can't access my workstation...

@richard67
Copy link
Member

richard67 commented Mar 24, 2020

@wilsonge Could you ckeck the conflict in the ApiController? Can it be that the pagination link is already ok with recently merged PR #27696 ? Or does it still need the change from this PR here in addition? I've stumpled over this when checking the merge conflicts here to 4.0-dev.

@richard67
Copy link
Member

@stefanoel I've made a pull request in your repository: stefanoel#1. This will update your PR here so it is up to date with its base branch, and solves the merge conflicts shown here on GitHub.

@wilsonge Please review the changes in libraries/src/MVC/Controller/ApiController.php as I mentioned above.

@richard67
Copy link
Member

@wilsonge @alikon Conflicts solved. Ready for review and testing.

@alikon
Copy link
Contributor

alikon commented Mar 24, 2020

great team-working
f***** covid19

@richard67
Copy link
Member

@wilsonge Drone failing the 2nd time now. No idea if related.

@wilsonge wilsonge merged commit 19578aa into joomla:4.0-dev Apr 4, 2020
@wilsonge
Copy link
Contributor

wilsonge commented Apr 4, 2020

This looks good to me! Thankyou!

@wilsonge wilsonge added this to the Joomla 4.0 milestone Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.