Pagination API REST

Hello,
On a un problème avec les API REST (en utilise RESTMappedObjectsExternalObject).
On a un problème de pagination, qui est aléatoire ( des fois on a des résultats avec la pagination et des fois on ne l’as pas). Il y a t-il un moyen pour forcer la pagination ( vu que nos connexes se basent dessus pour récupérer les données )

[Platform]
Status=OK
Version=5.1.54
BuiltOn=2022-10-31 15:49
Git=5.1/06cc2793ebaaa50ddf3f3dee2251b397d7bdc09b
Encoding=UTF-8
EndpointIP=10.144.23.150
EndpointURL=http://mla-api-7cc99bbd96-8w9fs:8080
TimeZone=Europe/Paris
SystemDate=2023-02-16 14:51:39

Cordialement,
Laila Bouzidi

Merci de préciser les appels que vous faites exactement sur ces APIs

Hello David,
On avait déjà ouvert un post sur les API : Problème de perte de données lors s'appel API
Ci-dessous un exemple ou on a bien la pagination
image

Par rapport à l’autre post avez vous fait la mise à jour ?
La révision à jour de la 5.1 est actuellement la 5.1.56

Et pour rappel la version mineure 5.1 est désormais totalement obsolète (elle n’est plus maintenue hors points critiques et uniquement sur demande). Il faudrait de toute façon envisager un passage en 5.2 (actuellement en 5.2.32) car on ne peut pas assurer de support ad vitam aeternam sur une version mineure obsolète

Sur l’exemple fourni les infos de pagination semblent cohérentes : 241 pages de 20 items = entre 4800 et 4820 records donc logique vs le count 4811

S’il y a des cas qui répondent des choses incohérentes c’est ça qui m’intéresse => il faudra alors comprendre le cas d’usage précis.

Je crois me rappeler que votre pb à l’époque était lié à de la consultation paginée se faisant alors que des traitements de chargement (ajouts/suppressions) étaient en cours sur les données consultées ce qui forcément peut aboutir à des choses bizarres.

Je ne vois pas trop comment il pourrait en être autrement => dans un tel contexte, coté client de l’API, il faut à minima relire les infos de pagination à chaque appel paginé pour actualiser le parcours (ex: revenir à la page 1 si le count à changé car sinon les résultats sont forcément imprévisibles)

Dans le cas que j’ai mis en capture, les résultats sont cohérents. Par contre on a des cas de retours d’appel API ou les éléments :
“pageCount”: 20,
“count”: 4811,
“page”: 1,
“maxPage”: 241
Sont absents, sachant que c’est le même appel API => comportement aléatoire

Les comportements “aléatoires” ça n’existe pas en informatique => Il y a des cas d’utilisation différents et/ou des contextes d’utilisation différents qui aboutissent à des résultats différents.

Il faut donc que vous essayiez de cerner les cas d’utilisation (et/ou le contexte) précis qui n’aboutissent pas à ce que vous souhaitez. Sans ces modes opératoires et/ou ces infos de contexte qui permettraient de reproduire le cas c’est impossible d’investiguer de notre coté.

Par exemple, pour essayer de cerner le contexte, est-ce que par hasard il y aurait des appels faits en // et concurrentes (ex: utilisation du même token pour des recherches différentes sur le même objet métier) ?

J’ai fait l’appel directement sur le back end avec une authentification (user/password) et on a pas le même résultats ( des fois on a la pagination et des fois on l’a pas )

Ci-dessous les deux cas :

{ “refined-triplets”: , “pageCount”: 0, “count”: 0, “page”: 1, “maxPage”: 1}

{“refined-triplets”:}

Le premier résultat est remonté à la première connexion, et dès qu’on réessaye l’appel on a plus la pagination

“aléatoire” ou “des fois” c’est pareil ça ne veut rien dire de concret…

Il faut que vous essayez de cerner précisément les cas/contextes d’utilisation (ex: enchainement précis des actions) qui aboutissent à un résultat non souhaité.

Ex: vous dites "J’ai fait l’appel directement sur le back end avec une authentification (user/password) " => via quel outil (curl, postman, navigateur, …) avec sur quel objet, avec quels attributs ? etc.

Nous avons besoin de ça pour essayer de reproduire le cas et pouvoir l’investiguer.

Je n’ai pas bien compris si c’est ça que vous faites mais appeler directement une API avec une authentification en basic auth (username/password) est un mode d’ident/authent obsolète (i.e. plus officiellement supporté) et donc non recommandé qui n’existe de toute façon plus à partir de la 5.2 (on l’avait laissé actif en 5.1 uniquement pour laisser le temps aux clients de basculer sur le mode token qui existe depuis la 4.0).

La bonne manière d’appeler les APIs c’est donc d’utiliser des tokens:

  1. obtenir un token:
curl -s -u monuser:monpassword"https://monurl/api/login?_output=json"
  1. utiliser ce token en bearer token tant que celui-ci est valide:
curl -s -H "Authorization: Bearer montoken" "https://monurl/api/rest/MonObjet"

NB: Selon votre configuration il est peut être aussi possible de passer le token en param de l’URL (le nom du param est confgurable):

curl -s "https://monurl/api/rest/MonObjet?_x_simplicite_authorization_=montoken"

Le même résultat est obtenu en utilisant Postman ( appel via un token) au premier appel on a la pagination et dès qu’on refait avec le même token on l’a plus.


sans_pagination

PS:

J’ai fait un test sur une 5.1 à jour (5.1.56) avec une API mappée (celle de la démo: module-demo-apis/DemoAPI1.java at master · simplicitesoftware/module-demo-apis · GitHub) et en utilisant une ident/authent token.

Je ne constate pas de différence de réponse lors d’appels successifs à cette API avec pagination:

> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<montoken>&_page=1" | jq '.count,.page,.maxPage'
63
1
2
> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<montoken>&_page=2" | jq '.count,.page,.maxPage'
63
2
2
> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<montoken>&_page=1" | jq '.count,.page,.maxPage'
63
1
2
> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<montoken>&_page=2" | jq '.count,.page,.maxPage'
63
2
2

etc.

La pagination s’affiche si on demande explicitement une page _page=N (avec N > 0)

Si on ne precise pas de page (ou qu’on met _page=0) c’est une réponse non paginée qu’on obtient

> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<mon token>" | jq '.count,.page,.maxPage'
null
null
null
> curl -s "https://testdaz.dev.simplicite.io/demo/v1/orders?_x_simplicite_authorization_=<mon token>" | jq '.orders | length'
63

Merci pour ton retour David.
On aimerait forcer la pagination sans rajouter le paramètre _page dans l’appel.
Y-il un moyen de le faire ?

Bonsoir @david, @lbouzidi cet échange me fait penser à ce que nous avons traité fin 2021 (échanges par mails du 16-17/12) où sous forte charge certaines réponses aux appels API pouvaient être interverties.

Tu avais finalement trouvé l’origine du pb le lendemain (ou dans la nuit) → servlet poolée | objet externe API mappées pas poolé | objets métier poolés. L’ajout d’un mécanisme de pooling des objets externes sur le endpoint API avait corrigé le problème.

Par contre ce correctif avait été intégré dans la 5.1.18.

Bonsoir @lbouzidi, j’ai implémenté ce mécanisme dans mes API. La pagination est activée par défaut sauf si le consommateur est explicitement autorisé à débrayer la pagination. ça fonctionne très bien et c’est relativement simple (je peux te faire une démo).

	@Override
	public Object get(Parameters params) throws HTTPException {
		...
		Object getResponse;
		int page = params.getIntParameter(CONST_PAGE_PARAM, 0);
		if (page <= 0) {
			params.getParameters().put(CONST_PAGE_PARAM, getGrant().getParameter(CONST_DEFAULT_PAGE_SYSPARAM,"1"));
		}
		int pagesize = params.getIntParameter(CONST_PAGESIZE_PARAM, 0);
		if (pagesize <= 0 || pagesize > getGrant().getIntParameter(CONST_MAX_PAGESIZE_SYSPARAM,20)) {
			params.getParameters().put(CONST_PAGESIZE_PARAM, getGrant().getParameter(CONST_DEFAULT_PAGESIZE_SYSPARAM,"20"));
		}
		...
		getResponse = super.get(params);
		...
		return getResponse;
	}



2 Likes

Merci @bmo pour cette réponse.

Il pourrait être possible de faire évoluer le RESTServiceExternalObject pour pouvoir indiquer qu’un objet doit être par défaut en mode paginé.

Et on pourrait alors faire en sorte que si on ajoute explicitement _page=0 ça veuille dire “appel non paginé”

Je passe donc de post en “feature request”

PS: Par contre, il s’agit bien d’une évolution donc ça pourra éventuellement être backporté jusque sur la release actuelle (la 5.2) mais pas sur une version antérieure plus maintenue comme la 5.1

2 Likes

L’évolution a été faite et backportée jusqu’à la release courante (5.2) => Ce sera disponible dans sa prochaine révision 5.2.33 prévue d’ici la fin de la semaine.

Il faudra utiliser une nouvelle variante de la méthode addObject() avec 2 arguments additionnels. Cf. cette Javadoc de la prerelease beta 5.3 (la méthode sera la même en 5.2.33): RESTMappedObjectsExternalObject

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.