IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

RESTFUL API avec critères + pagination


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Janvier 2006
    Messages
    716
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 716
    Par défaut RESTFUL API avec critères + pagination
    Bonjour,

    J'ai réussi à faire une api restful en C# qui permet de faire les opérations de base CRUD (create/read/update/delete).
    Je souhaite pouvoir passer des critères (filtres) en plus pour que lors de l'opération read la recherche soit filtré. Je recherche quelque chose qui pourrait s'implémenté de manière facile sur tous les objets (design pattern).
    Je souhaite aussi pouvoir gérer la pagination des données par lot de 50 enregistrements.

    Savez vous comment je peux faire ça et quels packages ou autres je pourrais utiliser pour faire cela ?

    Merci pour votre aide.

  2. #2
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Je suppose que utilises le framework asp mvc. Tu peux faire une méthode de contrôleur qui prend en paramètre une liste de critères, ainsi que les éléments de pagination et créée un filtre à partir de ces informations. Exemple avec une gestion de produits :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    public class Product
    {
    	public int Id { get; set; }
    	public string Name { get; set; }
    	public string Description { get; set; }
    	public double Price { get; set; }
    }
     
    public class SearchCriteria
    {
    	public string FieldName { get; set; }
    	public string Operator { get; set; }
    	public string Value { get; set; }
    }
     
    ["api/[controller]"]
    public class ProductController: ControllerBase
    {
    	[HttpGet("Search")]
    	public IEnumerable<Product> Search([FromQuery]IEnumerable<SearchCriteria> searchCriteria, [FromQuery]int? page, [FromQuery]int pageSize = 50)
    	{
    		IEnumerable<Product> result = null;
    		var predicates = new List<Func<Product, bool>>();
    		foreach(var criteria in searchCriteria)
    		{
    			var field = criteria.Field.ToLower();
    			var optr = criteria.Operator.ToLower();
    			var val = criteria.Value.ToLower();
    			switch(field)
    			{
    				case "id":
    					var id = int.Parse(val);
    					predicates.Add(p => p.Id == id);
    					break;
    				case "price":
    					var price = double.Parse(val);
    					if(optr == "lessthan") predicates.Add(p => p.Price < price);
    					if(optr == "morethan") predicates.Add(p => p.Price > price);
    					break;
    				case "name":
    					if(optr == "contains") predicates.Add(p => p.Name.ToLower().Contains(val));
    					if(optr == "notcontains") predicates.Add(p => !p.Name.ToLower().Contains(val));
    					if(optr == "startswith") predicates.Add(p => p.Name.ToLower().StartsWith(val));
    					if(optr == "endswith") predicates.Add(p => p.Name.ToLower().EndsWith(val));
    					break;
    				case "description":
    				// ...
    					break;
    				// gestion des autres critères...
    				default:
    					// propriété invalide : renvoyer une erreur ou ignorer
    			}
    		}
     
    		var result = _dataSource.Products.QueryAll().Where(product => predicates.All(p => p(product)); // récupération des données et application des critères
    		if(page.HasValue)
    		{
    			result = result.Skip(page.Value * pageSize).Take(pageSize); // pagination
    		}
    		return result;
    	}
    }
    À toi de définir une syntaxe de critères personnalisés. Je ne sais pas s'il est possible de passer tous les critères de cette façon dans l'url (attribut [FromQuery]), si ce n'est pas le cas on doit pouvoir passer par un formulaire (attribut [FromForm]). De même j'ai mis le code directement dans le contrôleur, mais il serait probablement plus approprié les gérer dans la couche de services.

    À vérifier également avec le standard http mais il est peut-être possible de gérer la pagination via les headers http (attributs range et assimilés).

  3. #3
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 972
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 972
    Par défaut
    Tout dépend de la complexité de tes API mais est-ce que tu as regardé du coté de ODATA ?
    Cela gère nativement ce genre problématique.

  4. #4
    Membre éclairé
    Inscrit en
    Janvier 2006
    Messages
    716
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 716
    Par défaut
    Merci pour vos réponses.

    En effet, j'utilise le framework MVC. Je cherche quelque chose où je n'aurai pas besoin de coder une classe de critères pour chaque Objet de la base de données.

    Je crois que OData ne descend pas les critères jusqu'au niveau de la base de données si j'ai bien compris ?
    Je préférerai que cela descende jusqu'à la base de données pour que cela soit plus performant ?

    J'ai trouvé cela mais ça ne me semble pas très connu et très utilisé :
    https://github.com/mrxten/QueryDesigner

  5. #5
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 972
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 972
    Par défaut
    Citation Envoyé par franfr57 Voir le message
    Je crois que OData ne descend pas les critères jusqu'au niveau de la base de données si j'ai bien compris ?
    Je préférerai que cela descende jusqu'à la base de données pour que cela soit plus performant ?
    Et bien, c'est une fausse croyance.
    J'utilise OData V4 couplé avec Entity Framwork
    Et lorsque je fais ce genre de requête donc avec pagination et filtres
    https://localhost:44343/ApiOData/Dossier?$top=10&$skip=5&$filter=(Verrou ne 'VER')

    J'obient la requête suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    exec sp_executesql N'SELECT 
        [Project1].[NODOSSIER] AS [NODOSSIER], 
        [Project1].[LIBELLE] AS [LIBELLE], 
        [Project1].[VERROU] AS [VERROU], 
        FROM ( SELECT 
            [Extent1].[NODOSSIER] AS [NODOSSIER], 
            [Extent1].[LIBELLE] AS [LIBELLE], 
            [Extent1].[VERROU] AS [VERROU],     
            FROM [dbo].[DOSSIER] AS [Extent1]
            WHERE  NOT (([Extent1].[VERROU] = @p__linq__0) AND ((CASE WHEN ([Extent1].[VERROU] IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END) = (CASE WHEN (@p__linq__0 IS NULL) THEN cast(1 as bit) ELSE cast(0 as bit) END)))
        )  AS [Project1]
        ORDER BY row_number() OVER (ORDER BY [Project1].[NODOSSIER] ASC)
        OFFSET @p__linq__1 ROWS FETCH NEXT @p__linq__2 ROWS ONLY ',N'@p__linq__0 varchar(8000),@p__linq__1 int,@p__linq__2 int',@p__linq__0='VER',@p__linq__1=5,@p__linq__2=10

  6. #6
    Membre éclairé
    Inscrit en
    Janvier 2006
    Messages
    716
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 716
    Par défaut
    OK.

    Dans ma solution, j'ai fait une séparation des 3 couches : API / Service (BLL) / Base de données (DAL).

    Quand je regarde des exemples sur OData la couche DAL est directement dans le contrôleur.
    Je ne vois pas trop comment faire pour l'implémenter dans mon projet ?
    J'utilise .NET Core 2.1 et Swagger, j'ai l'impression que la compatiblité entre les packages n'est pas certaine...+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Python 3.X] API Rest Openweathermap avec Python
    Par Nahtalie dans le forum Général Python
    Réponses: 8
    Dernier message: 04/01/2016, 19h38
  2. [PayPal] REST API avec PayPal
    Par Jolt0x dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 0
    Dernier message: 29/07/2013, 16h40
  3. Création d'un REST API avec silex pour une interface Backbone.js
    Par Overstone dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 08/09/2012, 13h18
  4. [2.x] besoin d information sur Rest API avec symfony2
    Par ESTYOUNES2008 dans le forum Symfony
    Réponses: 0
    Dernier message: 18/03/2012, 16h08
  5. Pagination avec critères
    Par Nelieru dans le forum Langage
    Réponses: 2
    Dernier message: 22/07/2010, 11h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo