Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Créer une API en C# avec Web API et Entity Framework 6

Par Jean-Baptiste EVIEUX Publié le 30/10/2016 à 23:26:55 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Ce tutoriel a pour but de vous enseigner les fondamentaux pour créer une API RESTful en C# ASP.NET en utilisant Web API 2 et Entity Framework 6. ASP.NET API est un framework qui facilite la création de services HTTP pour un large panel de clients, incluant les navigateurs et les applications mobiles. ASP.NET API est un framework idéal pour la création d'applications RESTful en .NET. Dans ce tutoriel, nous allons créer une API REST qui va nous permettre d'enregistrer, modifier, lister et supprimer des livres ainsi que leurs auteurs. L'API REST exposera les actions suivantes:

Action Description
GET /api/authors Retourne la liste des auteurs
GET /api/authors/{id} Retourne un auteur via son id
POST /api/authors Ajoute un auteur
PUT /api/authors/{id} Met à jour un auteur existant
DELETE /api/authors/{id} Supprime un auteur via son id
GET /api/books Retourne la liste des livres
GET /api/books/{id} Retourne un livre via son id
POST /api/books Ajoute un livre
PUT /api/books/{id} Met à jour un livre existant
DELETE /api/books/{id} Supprime un livre via son id

Prérequis

Avant de commencer, il va vous falloir installer des prérequis:

Création du projet

Après avoir installé les prérequis, nous allons créer le projet dans Visual Studio. Pour cela, cliquez sur Fichier > Nouveau > Projet, sélectionnez ASP.NET Web Application, nommez le projet BookApi et cliquez sur OK:

Sur la fenêtre suivante, sélectionnez le template Vide et avec l'option Web API de cochée. Décochez également la case Héberger dans le cloud puis cliquez sur OK.

Vous devriez obtenir la structure suivante:

Le dossier Controllers contiendra tous nos contrôleurs. Un contrôleur est chargé de réceptionner et traiter les requêtes HTTP ainsi que de retourner une réponse au client.

Le dossier Models quant à lui contiendra nos modèles. Un modèle représente une entité de notre application comme par exemple l'entité Book pour représenter un livre ou bien l'entité Author pour représenter un auteur.

Avant de rentrer dans le vif du sujet, nous allons rapidement modifier les propriétés du projet pour éviter des comportements que je trouve gênant personnellement. Faites un clic droit sur le projet puis cliquez sur Propriétés puis, dans la catégorie Web modifier les propriétés suivantes:

  • Dans la section Action de démarrage, sélectionnez Ne pas ouvrir de page. Attendre une demande émanent d'une application externe ce qui évitera que Visual Studio ouvre un nouvel onglet dans votre navigateur car de toute manière nous allons utiliser Postman pour tester notre API.

  • Dans la section Débogueurs décochez la case Activer Modifier Continuer afin que notre API ne s'arrête lorsqu'on arrête le débogueur.

(Vous noterez également l'url de notre API encadrez en orange, c'est l'adresse que nous utiliserons plus tard dans Postman afin de tester notre API)

Une fois ces deux propriétés modifiées, faites une sauvegarde et fermez ensuite cette page de propriétés.

Ajout d'Entity Framework

Pour gérer l'accès à notre base de données, nous allons utiliser Entity Framework qu'il faut ajouter à notre projet en passant par le gestionnaire de paquet NuGet. Pour cela, cliquez sur Outils > Gestionnaire de package NuGet > Gérer les package NuGet pour la solution ...

Dans la fenêtre qui s'ouvrira, sélectionnez la catégorie En ligne > nuget.org, sélectionnez Entity Framework puis cliquez sur Installer.

Note: Au moment je rédige ce tutoriel, la dernière version stable est la 6.1.3 si ce n'est pas le cas et que vous désirez obtenir cette version spécifique, il suffit d'ouvrir la console du gestionnaire de package situé dans Outils > Gestionnaire de package NuGet > Console du Gestionnaire de package et d'exécuter la commande suivante:

Install-Package EntityFramework -Version 6.1.3

Une fois Entity Framework installé nous pouvons enfin entrer dans le vif du sujet.

Ajout des modèles

Nous allons commencer le développement de notre API en créant tout d'abord nos modèles auteur et livre en ajoutant deux nouvelles classes Author et Book dans le dossier Models. Pour ajouter une classe, faites un clic droit sur le dossier, puis Ajouter > Classe...

Remplacer ensuite le code du fichier Author.cs par celui-ci:

using System.ComponentModel.DataAnnotations;

namespace BookApi.Models
{
    public class Author
    {
        public int Id { get; set; }

        [Required]
        public string Firstname { get; set; }

        [Required]
        public string Lastname { get; set; }
    }
}

Nous pouvons voir que cette classe possède 3 propriétés : Id, Firstname et Lastname. Par convention, Entity Framework reconnaîtra la propriété Id de type int comme identifiant de la classe et la traitera comme clé primaire pour cette entité. De plus, si la propriété est un nombre (ici un int), il ajoutera également la fonctionnalité d'auto incrémentation ce qui permettra de déléguer la génération de l'Id lors de la création d'une nouvelle entité et sera incrémenté de 1 à chaque nouvelle entité créé en base. L'id sera donc généré et assigné automatiquement au moment de la sauvegarde de l'entité en base.

Pour qu'une propriété ne faisant pas partie des conventions d'Entity Framework soit considéré comme clé primaire, il faut lui ajouter l'annotation [Key] comme ceci:

[Key]
public int Id { get; set; }

Vous aurez également noté la présence de l'annotation [Required] sur les propriétés Firstname et Lastname: ça nous permet d'indiquer qu'il est nécessaire à ces deux propriétés d'avoir obligatoirement une valeur de renseignée. Il sera alors impossible de créer un auteur sans prénom ou sans nom de famille. Pour la clé primaire de la classe (Id) cette annotation est implicite et n'est donc pas nécessaire de renseigner.

Remplacez ensuite le code du fichier Book.cs par celui-ci:

using System;
using System.ComponentModel.DataAnnotations;

namespace BookApi.Models
{
    public class Book
    {
        public int Id { get; set; }

        [Required]
        public string Title { get; set; }

        public DateTime? ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }

        // Foreign Key
        [Required]
        public int AuthorId { get; set; }

        // Navigation property
        public Author Author { get; set; }
    }
}

Cette classe est plutôt très similaire à la classe Author à 2 nouveautés près. Pour commencer, vous aurez peut-être remarqué la présence du caractère ? qui suit le type DateTime de la propriété ReleaseDate:

public DateTime? ReleaseDate { get; set; }
// Ce qui est l'équivalent de
public Nullable<DateTime> ReleaseDate { get; set; }

Ce caractère indique que la propriété RealeaseDate est optionnel en autorisant la valeur null. En effet, il est possible qu'un utilisateur veuille enregistrer un livre qui n'a pas encore été publié ou édité.

L'autre nouveauté par rapport à la classe Author est la présence des propriétés Author et AuthorId. Comme un auteur peut avoir écrit 0 ou plusieurs livres et que dans ce tutoriel, j'ai voulu resté simple en admettant qu'un livre ne peut avoir été écrit que par un seul auteur, nous sommes donc dans une relation One-To-Many (1:n) et c'est par conséquent la classe Book qui porte l'information grâce à la propriété AuthorId qui aura pour valeur l'id de l'auteur qui l'a écrit.

La propriété Author est une propriété de navigation (car elle porte le même nom que la propriété AuthorId moins "Id"). Grâce à ces deux propriétés Entity Framework comprends que nous souhaitons créer une relation One-To-Many entre l'entité Author et l'entité Book. La propriété de navigation Author dans la classe Book sera automatiquement créée et assignée lorsqu'on récupérera un livre de la base de donnée et ainsi accéder aux informations concernant l'auteur directement depuis le livre comme par exemple son prénom:

Book someBook = db.Books.Find(1); // Récupération depuis la base de donnée
Console.WriteLine(someBook.Author.Firstname); // Affiche le prénom de l'auteur dans la console

Une fois les modèles créés, il faut également créer un DbContext qui représente la connexion à notre base de données afin qu'Entity Framework puisse travailler avec cette dernière. Nous allons le faire dans la prochaine section lorsque nous allons ajouter notre premier contrôleur.

Ajout des controlleurs

Avant de générer les contrôleurs pour nos entités, essayons d'abord de compiler la solution Générer > Générer la solution (ou Ctrl+Shift+B). Si vous avez copié ou réécrit la classe correctement, la solution devrait parfaitement compiler.

Pour créer le contrôleur de l'entité Author, il faut que vous fassiez un clic droit sur le dossier Controllers puis Ajouter > Contrôleur ...

Dans la fenêtre qui s'affiche, sélectionnez Web API 2 Controller with Actions using Entity Framework puis validez en appuyant sur le bouton Ajouter.

Dans la fenêtre qui suit, pour le champ Modèle de classe, faites dérouler la liste et sélectionnez la classe Author. Si votre liste est vide ou si votre classe n'est pas listée, c'est qu'il vous faut recompiler votre solution.

Pour la Classe de contexte de données, nous n'en avons pas encore créé, il faut donc cliquer sur l'icône avec le +, Visual Studio vous propose alors dans une nouvelle fenêtre un nom pour votre nouveau DbContext que vous pouvez modifier si besoin (BookApi.Models.BookApiContext) puis validez en cliquant sur Ajouter.

Cochez ensuite la case Utiliser les actions asynchrones du contrôleur. Cette case permet d'indiquer à Visual Studio que l'on souhaite qu'il nous génère les actions de notre contrôleur en version asynchrone et qu'il doit également utiliser les méthodes asynchrones d'Entity Framework.

Vérifiez le Nom du contrôleur proposé automatiquement (AuthorsController) et finalisez la création du contrôleur en cliquant sur Ajouter.

Répétez l'opération pour créer un autre contrôleur mais cette fois-ci pour l'entité Book et en sélectionnant notre BookApiContext déjà créé à l'étape précédente.

En créant nos deux contrôleurs, Visual Studio doit nous avoir généré trois nouveaux fichiers:

  • Controllers/AuthorsController.cs

    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System.Web.Http.Description;
    using BookApi.Models;
    
    namespace BookApi.Controllers
    {
        public class AuthorsController : ApiController
        {
            private BookApiContext db = new BookApiContext();
    
            // GET: api/authors
            public IQueryable<Author> GetAuthors()
            {
                return db.Authors;
            }
    
            // GET: api/authors/5
            [ResponseType(typeof (Author))]
            public async Task<IHttpActionResult> GetAuthor(int id)
            {
                Author author = await db.Authors.FindAsync(id);
                if (author == null)
                {
                    return NotFound();
                }
    
                return Ok(author);
            }
    
            // PUT: api/authors/5
            [ResponseType(typeof (void))]
            public async Task<IHttpActionResult> PutAuthor(int id, Author author)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                if (id != author.Id)
                {
                    return BadRequest();
                }
    
                db.Entry(author).State = EntityState.Modified;
    
                try
                {
                    await db.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!AuthorExists(id))
                    {
                        return NotFound();
                    }
                    throw;
                }
    
                return StatusCode(HttpStatusCode.NoContent);
            }
    
            // POST: api/authors
            [ResponseType(typeof (Author))]
            public async Task<IHttpActionResult> PostAuthor(Author author)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                db.Authors.Add(author);
                await db.SaveChangesAsync();
    
                return CreatedAtRoute("DefaultApi", new {id = author.Id}, author);
            }
    
            // DELETE: api/authors/5
            [ResponseType(typeof (Author))]
            public async Task<IHttpActionResult> DeleteAuthor(int id)
            {
                Author author = await db.Authors.FindAsync(id);
                if (author == null)
                {
                    return NotFound();
                }
    
                db.Authors.Remove(author);
                await db.SaveChangesAsync();
    
                return Ok(author);
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    db.Dispose();
                }
                base.Dispose(disposing);
            }
    
            private bool AuthorExists(int id)
            {
                return db.Authors.Count(e => e.Id == id) > 0;
            }
        }
    }
  • Controllers/BooksController.cs

    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System.Web.Http.Description;
    using BookApi.Models;
    
    namespace BookApi.Controllers
    {
        public class BooksController : ApiController
        {
            private BookApiContext db = new BookApiContext();
    
            // GET: api/books
            public IQueryable<Book> GetBooks()
            {
                return db.Books.Include(b => b.Author);
            }
    
            // GET: api/books/5
            [ResponseType(typeof (Book))]
            public async Task<IHttpActionResult> GetBook(int id)
            {
                Book book = await db.Books.Include(b => b.Author).SingleOrDefaultAsync(b => b.Id == id);
                if (book == null)
                {
                    return NotFound();
                }
    
                return Ok(book);
            }
    
            // PUT: api/books/5
            [ResponseType(typeof (void))]
            public async Task<IHttpActionResult> PutBook(int id, Book book)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                if (id != book.Id)
                {
                    return BadRequest();
                }
    
                db.Entry(book).State = EntityState.Modified;
    
                try
                {
                    await db.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!BookExists(id))
                    {
                        return NotFound();
                    }
                    throw;
                }
    
                return StatusCode(HttpStatusCode.NoContent);
            }
    
            // POST: api/books
            [ResponseType(typeof (Book))]
            public async Task<IHttpActionResult> PostBook(Book book)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
    
                db.Books.Add(book);
                await db.SaveChangesAsync();
    
                return CreatedAtRoute("DefaultApi", new {id = book.Id}, book);
            }
    
            // DELETE: api/books/5
            [ResponseType(typeof (Book))]
            public async Task<IHttpActionResult> DeleteBook(int id)
            {
                Book book = await db.Books.FindAsync(id);
                if (book == null)
                {
                    return NotFound();
                }
    
                db.Books.Remove(book);
                await db.SaveChangesAsync();
    
                return Ok(book);
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    db.Dispose();
                }
                base.Dispose(disposing);
            }
    
            private bool BookExists(int id)
            {
                return db.Books.Count(e => e.Id == id) > 0;
            }
        }
    }
  • Models/BookApiContext.cs

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Web;
    
    namespace BookApi.Models
    {
        public class BookApiContext : DbContext
        {
            // You can add custom code to this file. Changes will not be overwritten.
            // 
            // If you want Entity Framework to drop and regenerate your database
            // automatically whenever you change your model schema, please use data migrations.
            // For more information refer to the documentation:
            // http://msdn.microsoft.com/en-us/data/jj591621.aspx
        
            public BookApiContext() : base("name=BookApiContext")
            {
            }
    
            public System.Data.Entity.DbSet<BookApi.Models.Author> Authors { get; set; }
    
            public System.Data.Entity.DbSet<BookApi.Models.Book> Books { get; set; }
        
        }
    }

    Le "name=BookApiContext" que vous pouvez apercevoir correspond au nom de la connectionString à utiliser pour initialiser notre context et correspond à la manière d'accéder à notre base de donnée. Cette connectionString a dû être rajouté automatiquement dans notre Web.config lorsque nous avons généré notre DbContext lors de la création de notre AuthorsController et devrait ressembler à ceci:

    <connectionStrings>
        <add name="BookApiContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=BookApiContext-20161030135228; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|BookApiContext-20161030135228.mdf" providerName="System.Data.SqlClient" />
    </connectionStrings>

    Cette connectionString nous indique que la base de données sera de type localdb et que son nom sera BookApiContext-20161030135228

Test des contrôleurs

Une fois les contrôleurs créés, nous pouvons dès maintenant les essayer grâce à notre client Postman. Pour commencer, lancez le projet depuis Visual Studio et rendez-vous ensuite sur votre application Postman.

GET /api/authors

Faisons un premier test en essayant de récupérer la liste des auteurs enregistrés (comme c'est une nouvelle base de donnée, le résultat est une liste vide):

Vous aurez forcément remarqué la lenteur du contrôleur à traiter notre simple GET et nous retourner une liste vide. En réalité, comme c'était la première fois que nous appelions notre API et que la base de données n'a pas été créée, Entity Framework s'est donc chargé de la créer pour nous en respectant les propriétés de chaque modèles ainsi que leurs relations. Sur la capture d'écran précédente, cette étape a pris environ 62 secondes. Pour le prouver, nous pouvons visualiser notre base de données grâce à l'outils Explorateur de serveurs de Visual Studio que vous pourrez trouver dans Affichage > Explorateur de serveurs. Réalisez ensuite un clic droit sur Connexions de données puis sur Ajouter une connexion ...

Dans la fenêtre qui s'affiche, renseignez (localdb)\v11.0 dans le nom du serveur (rappelez-vous de notre connectionString) puis faites dérouler le champ Sélectionner ou entrer un nom de base de données afin d'y sélectionner notre base de données BookApiContext-20161030135228. Ajoutez la connexion à cette base de données en cliquant sur le bouton OK.

Vous devriez obtenir quelque chose de similaire dans votre fenêtre d'Explorateur de serveurs:

Vous remarquerez également qu'Entity Framework nous a également créé une table supplémentaire appelée _MigrationHistory et permet de gérer les changements apportés aux différents modèles et donc, par conséquent, à la structure de la base de données. Pour en savoir plus sur l'utilisation et la gestion des migrations, reportez-vous à cette page MSDN: Migrations Entity Framework Code First

Une nouvelle exécution de la requête GET /api/authors me retourne à nouveau une liste vide mais cette fois-ci en seulement 25 millisecondes ce qui est, vous serez d'accord, plus appropriés pour une API que les 62 secondes de la première réponse.

POST /api/authors

Pour enregistrer un nouvel auteur dans notre base de données, il suffit de faire une requête POST sur l'endpoint /api/authors et de donner en corps/body de la requête, la représentation au format JSON de notre nouvel auteur à enregistrer (Il ne faut pas renseigner la propriété Id de l'auteur car elle sera automatiquement générée pour nous:

{
    "Firstname" : "Blanche",
    "Lastname" : "McMannus"
}

La requête et la réponse dans Postman:

Notre contrôleur à bien enregistré notre nouvel auteur et nous a également retourné en réponse la représentation complète de notre auteur avec son Id fraichement assigné. Pour vérifier, nous pouvons réexécuter la commande GET /api/autors:

PUT /api/authors/{id}

Il s'avère que notre auteur Blanche McMannus ne prend en réalité qu'un seul 'n' dans son nom de famille. Pour corriger cela, nous pouvons modifier notre auteur portant l'id 1 grâce à une requête PUT sur l'endpoint /api/authors/1 et avec le corps/body JSON suivant:

{
    "Id" : 1,
    "Firstname" : "Blanche",
    "Lastname" : "McManus"
}

Vous noterez que le contrôleur ne nous renvoie la version corrigée dans la réponse de notre requête. Seul le code de retour (204 No Content) nous permet d'attester du succès de la requête. Nous allons quand même vérifier la modification grâce à la requête de la section suivante.

GET /api/authors/{id}

Maintenant que nous avons un auteur avec un nom corrigé et un id, nous pouvons tester l'endpoint GET /api/authors/{id} qui va nous permettre de récupérer l'auteur qui possède un id spécifique. Nous venons de voir que notre auteur Blanche McManus possède l'id 1; essayons donc une requête GET sur l'endpoint /api/authors/1:

Comme prévue, notre contrôleur nous a retourné qu'un seul auteur (vous remarquerez que la réponse n'est pas une liste par l'absence des crochets [ ]) et c'est bien l'auteur Blanche McManus que nous attendions et dont on vient de corriger le nom de famille.

GET /api/books

Essayons maintenant de récupérer la liste des livres enregistrés en base de données grâce à une requête GET sur l'endpoint /api/books:

Comme l'on pouvait s'y attendre, le contrôleur nous a retourné une liste vide. Sans plus attendre, ajoutons un livre en passant à la section suivante.

POST /api/books

Pour enregistrer un nouveau livre, nous allons envoyer une requête POST sur l'endpoint /api/books avec le corps/body JSON suivant:

{
    "Title" : "Our Little Scotch Cousin",
    "AuthorId" : 1
}

Vous aurez remarquez que je n'ai renseigné que les champs obligatoires (propriétés portant l'annotation [Required]), les autres champs prendrons une valeur par défaut (pour les champs nullable, il prendrons la valeur null et 0 pour les champs de type nombre). Pour le champ AuthorId qui est obligatoire (il ne peut pas y avoir de livre sans qu'il ait un auteur) j'ai renseigné l'id de notre auteur Blanche McManus qui possède l'id 1. Exécutons la requête POST et voyons le résultat:

L'enregistrement du livre pour notre auteur a bien fonctionné et une nouvelle requête GET sur l'endpoint /api/books nous permet de vérifier sa sauvegarde en base de données:

Vous aurez peut-être constaté que notre contrôleur nous retourne le livre avec ces différentes propriétés dont l'AuthorId qui est correct mais il nous retourne pas l'auteur correspondant qui reste à null. C'est dû au fait que les relations ne sont pas automatiquement chargées avec l'entité. Nous allons corriger cela dans la section suivante.

Charger automatiquement l'auteur avec le livre

Pour corriger le problème que l'on vient d'observer, nous allons modifier les méthodes GetBooks, GetBook et DeleteBook du contrôleur BooksController.

La méthode GetBooks est extrêmement simple et ressemble à ceci:

public IQueryable<Book> GetBooks()
{
    return db.Books;
}

Pour demander à Entity Framework de nous charger également la propriété Author, il suffit d'utiliser la méthode Include:

public IQueryable<Book> GetBooks()
{
    return db.Books.Include(b => b.Author);
}

Pour la méthode GetBook qui ressemble à ceci:

public async Task<IHttpActionResult> GetBook(int id)
{
    Book book = await db.Books.FindAsync(id);
    if (book == null)
    {
        return NotFound();
    }

    return Ok(book);
}

la modification est légèrement plus compliquée puisque la méthode FindAsync ne peut pas être utilisée avec la méthode Include. Néanmoins, il faut savoir que cette méthode FindAsync(id) est un raccourcis pour SingleOrDefaultAsync(b => b.Id == id) qui, elle, est compatible avec la méthode Include:

public async Task<IHttpActionResult> GetBook(int id)
{
    Book book = await db.Books.Include(b => b.Author).SingleOrDefaultAsync(b => b.Id == id);
    if (book == null)
    {
        return NotFound();
    }

    return Ok(book);
}

Et enfin la méthode DeleteBook qui doit être remplacé par le code suivant:

public async Task<IHttpActionResult> DeleteBook(int id)
{
    Book book = await db.Books.Include(b => b.Author).SingleOrDefaultAsync(b => b.Id == id);
    if (book == null)
    {
        return NotFound();
    }

    db.Books.Remove(book);
    await db.SaveChangesAsync();

    return Ok(book);
}

Maintenant lorsque nous envoyons une requête GET sur l'endpoint /api/books par exemple, nous obtenons également l'auteur dans la réponse:

Nous venons de mettre en place ce qu'on appelle la méthode du "eager loading", pour en savoir plus sur les méthodes de chargement des entités liées reportez-vous à la documentation MSDN suivante: Entity Framework Loading Related Entities

PUT /api/books

Nous pouvons tester la mise à jour d'un livre en envoyant une requête PUT sur l'endpoint /api/books/1 avec le corps/body suivant:

{
    "Id" : 1,
    "Title" : "Our Little Scotch Cousin",
    "RealeaseDate" : "2013-08-24T14:00:00Z",
    "Genre" : "Fiction",
    "Price" : 10.00,
    "AuthorId" : 1
}

GET /api/books/{id}

Afin de vérifier les modifications apportées sur le livre 1 mais également pour vérifier le bon fonctionnement de notre méthode GetBook que nous avons modifié en ajoutant "l'eager loading" de l'auteur, nous allons faire une requête GET sur l'endpoint /api/books/1:

La nouvelle réponse nous prouve que les modifications apportées ont bien été prises en compte et que le chargement automatique de l'auteur avec le livre fonctionne également.

DELETE /api/books/{id}

Nous pouvons maintenant tester la suppression d'un livre via son id. Pour cela, nous allons supprimer le livre "Our Little Scotch Cousin" de Blanche McManus portant l'id 1 en envoyant une requête DELETE sur l'endpoint /api/books/1:

Si tout s'est bien passé, une requête GET sur l'endpoint /api/books/1 devrait nous retourner une erreur 404 Not Found:

Comme prévu, la requête nous a retourné une erreur 404 Not Found puisque le livre dont l'id est 1 a été supprimé par la requête DELETE.

DELETE /api/authors/{id}

Nous allons terminer les tests par la suppression d'un auteur via son id. L'auteur Blanche McManus possède l'id 1 donc pour la supprimer de notre base de données, nous allons envoyer une requête DELETE sur l'endpoint /api/authors/1:

Et de la même manière que pour la suppression d'un livre, nous pouvons tester la suppression de l'auteur en envoyant une requête GET sur l'endpoint /api/authors/1:

Comme prévu, le contrôleur ne trouve pas en base l'auteur portant l'id 1 et nous retourne par conséquent une erreur 404 Not Found.

Conclusion

Pour conclure ce tutoriel, nous avons vu avec quelle facilité il est possible de créer une API RESTful fonctionnelle avec les méthodes de CRUD (Create, Read, Update, Delete) et une persistance des données assurée par Entity Framework et une base de données SQL Express.

Pour aller plus loin et en apprendre d'avantage sur les fonctionnalités de la Web API 2 comme par exemple la sécurisation ou la gestion des différentes versions de votre API, reportez-vous sur ce site: https://www.asp.net/web-api

Téléchargements

Le projet terminé peut être téléchargé ci-après (Solution Visual Studio 2013): BookApi.zip

Vous pouvez également télécharger et importer la collection Postman avec toutes les méthodes des contrôleurs: BookApi.postman_collection.json

Sources et références

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels