9

Postman est un outil qui peut être utilisé pour tester facilement les services Web reposants.Comment générer des collections JMAN Postman à partir d'un projet WebApi2 à l'aide de WebApi HelpPages qui sont adaptés à l'importation

Si un projet Asp.Net utilise WebApi conjointement avec WebApi Helppages documents peuvent être générés automatiquement pour les services Web reposant exposés.

Cette documentation autogénérée est bonne, mais elle pourrait être améliorée grâce à une accessibilité accrue.

Comment ces technologies peuvent-elles être combinées pour générer un fichier JSON qui peut être importé dans Postman?

Répondre

13

sur le poste Expanding blog « Using ApiExplorer to export API information to PostMan, a Chrome extension for testing Web APIs » il est possible de générer un fichier JSON qui peut être importé dans Postman pour une utilisation dans les tests et la documentation.

Vous devez d'abord contrôleur aa de configuration qui permet d'exporter JSON

/// <summary> 
///  Based on 
///  http://blogs.msdn.com/b/yaohuang1/archive/2012/06/15/using-apiexplorer-to-export-api-information-to-postman-a-chrome-extension-for-testing-web-apis.aspx 
/// </summary> 
[RoutePrefix("api/postman")] 
public class PostmanApiController : ApiController 
{ 
    /// <summary> 
    ///  Produce [POSTMAN](http://www.getpostman.com) related responses 
    /// </summary> 
    public PostmanApiController() 
    { 
     // exists for documentation purposes 
    } 

    private readonly Regex _pathVariableRegEx = new Regex("\\{([A-Za-z0-9-_]+)\\}", RegexOptions.ECMAScript | RegexOptions.Compiled); 
    private readonly Regex _urlParameterVariableRegEx = new Regex("=\\{([A-Za-z0-9-_]+)\\}", RegexOptions.ECMAScript | RegexOptions.Compiled); 

    /// <summary> 
    ///  Get a postman collection of all visible Api 
    ///  (Get the [POSTMAN](http://www.getpostman.com) chrome extension) 
    /// </summary> 
    /// <returns>object describing a POSTMAN collection</returns> 
    /// <remarks>Get a postman collection of all visible api</remarks> 
    [HttpGet] 
    [Route(Name = "GetPostmanCollection")] 
    [ResponseType(typeof (PostmanCollectionGet))] 
    public IHttpActionResult GetPostmanCollection() 
    { 
     return Ok(this.PostmanCollectionForController()); 
    } 

    private PostmanCollectionGet PostmanCollectionForController() 
    { 
     var requestUri = Request.RequestUri; 
     var baseUri = requestUri.Scheme + "://" + requestUri.Host + ":" + requestUri.Port 
         + HttpContext.Current.Request.ApplicationPath; 

     var postManCollection = new PostmanCollectionGet 
           { 
            Id = Guid.NewGuid(), 
            Name = "[Name of your API]", 
            Timestamp = DateTime.Now.Ticks, 
            Requests = new Collection<PostmanRequestGet>(), 
            Folders = new Collection<PostmanFolderGet>(), 
            Synced = false, 
            Description = "[Description of your API]" 
           }; 


     var helpPageSampleGenerator = Configuration.GetHelpPageSampleGenerator(); 

     var apiExplorer = Configuration.Services.GetApiExplorer(); 

     var apiDescriptionsByController = apiExplorer.ApiDescriptions.GroupBy(
      description => 
      description.ActionDescriptor.ActionBinding.ActionDescriptor.ControllerDescriptor.ControllerType); 

     foreach (var apiDescriptionsByControllerGroup in apiDescriptionsByController) 
     { 
      var controllerName = apiDescriptionsByControllerGroup.Key.Name.Replace("Controller", string.Empty); 

      var postManFolder = new PostmanFolderGet 
           { 
            Id = Guid.NewGuid(), 
            CollectionId = postManCollection.Id, 
            Name = controllerName, 
            Description = string.Format("Api Methods for {0}", controllerName), 
            CollectionName = "api", 
            Order = new Collection<Guid>() 
           }; 

      foreach (var apiDescription in apiDescriptionsByControllerGroup 
       .OrderBy(description => description.HttpMethod, new HttpMethodComparator()) 
       .ThenBy(description => description.RelativePath) 
       .ThenBy(description => description.Documentation.ToString(CultureInfo.InvariantCulture))) 
      { 
       TextSample sampleData = null; 
       var sampleDictionary = helpPageSampleGenerator.GetSample(apiDescription, SampleDirection.Request); 
       MediaTypeHeaderValue mediaTypeHeader; 
       if (MediaTypeHeaderValue.TryParse("application/json", out mediaTypeHeader) 
        && sampleDictionary.ContainsKey(mediaTypeHeader)) 
       { 
        sampleData = sampleDictionary[mediaTypeHeader] as TextSample; 
       } 

       // scrub curly braces from url parameter values 
       var cleanedUrlParameterUrl = this._urlParameterVariableRegEx.Replace(apiDescription.RelativePath, "=$1-value"); 

       // get pat variables from url 
       var pathVariables = this._pathVariableRegEx.Matches(cleanedUrlParameterUrl) 
             .Cast<Match>() 
             .Select(m => m.Value) 
             .Select(s => s.Substring(1, s.Length - 2)) 
             .ToDictionary(s => s, s => string.Format("{0}-value", s)); 

       // change format of parameters within string to be colon prefixed rather than curly brace wrapped 
       var postmanReadyUrl = this._pathVariableRegEx.Replace(cleanedUrlParameterUrl, ":$1"); 

       // prefix url with base uri 
       var url = baseUri.TrimEnd('/') + "/" + postmanReadyUrl; 

       var request = new PostmanRequestGet 
           { 
            CollectionId = postManCollection.Id, 
            Id = Guid.NewGuid(), 
            Name = apiDescription.RelativePath, 
            Description = apiDescription.Documentation, 
            Url = url, 
            Method = apiDescription.HttpMethod.Method, 
            Headers = "Content-Type: application/json", 
            Data = sampleData == null 
              ? null 
              : sampleData.Text, 
            DataMode = "raw", 
            Time = postManCollection.Timestamp, 
            Synced = false, 
            DescriptionFormat = "markdown", 
            Version = "beta", 
            Responses = new Collection<string>(), 
            PathVariables = pathVariables 
           }; 

       postManFolder.Order.Add(request.Id); // add to the folder 
       postManCollection.Requests.Add(request); 
      } 

      postManCollection.Folders.Add(postManFolder); 
     } 

     return postManCollection; 
    } 
} 

/// <summary> 
///  Quick comparer for ordering http methods for display 
/// </summary> 
internal class HttpMethodComparator : IComparer<HttpMethod> 
{ 
    private readonly string[] _order = 
    { 
     "GET", 
     "POST", 
     "PUT", 
     "DELETE" 
    }; 

    public int Compare(HttpMethod x, HttpMethod y) 
    { 
     return Array.IndexOf(this._order, x.ToString()).CompareTo(Array.IndexOf(this._order, y.ToString())); 
    } 
} 

et générer les modèles appropriés:

Un pour la PostManCollection

/// <summary> 
///  [Postman](http://getpostman.com) collection representation 
/// </summary> 
public class PostmanCollectionGet 
{ 
    /// <summary> 
    ///  Id of collection 
    /// </summary> 
    [JsonProperty(PropertyName = "id")] 
    public Guid Id { get; set; } 

    /// <summary> 
    ///  Name of collection 
    /// </summary> 
    [JsonProperty(PropertyName = "name")] 
    public string Name { get; set; } 

    /// <summary> 
    ///  Collection generation time 
    /// </summary> 
    [JsonProperty(PropertyName = "timestamp")] 
    public long Timestamp { get; set; } 

    /// <summary> 
    ///  Requests associated with the collection 
    /// </summary> 
    [JsonProperty(PropertyName = "requests")] 
    public ICollection<PostmanRequestGet> Requests { get; set; } 

    /// <summary> 
    ///  **unused always false** 
    /// </summary> 
    [JsonProperty(PropertyName = "synced")] 
    public bool Synced { get; set; } 

    /// <summary> 
    ///  folders within the collection 
    /// </summary> 
    [JsonProperty(PropertyName = "folders")] 
    public ICollection<PostmanFolderGet> Folders { get; set; } 

    /// <summary> 
    ///  Description of collection 
    /// </summary> 
    [JsonProperty(PropertyName = "description")] 
    public string Description { get; set; } 
} 

Un pour la PostmanFolder

/// <summary> 
///  Object that describes a [Postman](http://getpostman.com) folder 
/// </summary> 
public class PostmanFolderGet 
{ 
    /// <summary> 
    ///  id of the folder 
    /// </summary> 
    [JsonProperty(PropertyName = "id")] 
    public Guid Id { get; set; } 

    /// <summary> 
    ///  folder name 
    /// </summary> 
    [JsonProperty(PropertyName = "name")] 
    public string Name { get; set; } 

    /// <summary> 
    ///  folder description 
    /// </summary> 
    [JsonProperty(PropertyName = "description")] 
    public string Description { get; set; } 

    /// <summary> 
    ///  ordered list of ids of items in folder 
    /// </summary> 
    [JsonProperty(PropertyName = "order")] 
    public ICollection<Guid> Order { get; set; } 

    /// <summary> 
    ///  Name of the collection 
    /// </summary> 
    [JsonProperty(PropertyName = "collection_name")] 
    public string CollectionName { get; set; } 

    /// <summary> 
    ///  id of the collection 
    /// </summary> 
    [JsonProperty(PropertyName = "collection_id")] 
    public Guid CollectionId { get; set; } 
} 

Enfin, un modèle pour le PostmanRequest

/// <summary> 
///  [Postman](http://getpostman.com) request object 
/// </summary> 
public class PostmanRequestGet 
{ 
    /// <summary> 
    ///  id of request 
    /// </summary> 
    [JsonProperty(PropertyName = "id")] 
    public Guid Id { get; set; } 

    /// <summary> 
    ///  headers associated with the request 
    /// </summary> 
    [JsonProperty(PropertyName = "headers")] 
    public string Headers { get; set; } 

    /// <summary> 
    ///  url of the request 
    /// </summary> 
    [JsonProperty(PropertyName = "url")] 
    public string Url { get; set; } 

    /// <summary> 
    ///  path variables of the request 
    /// </summary> 
    [JsonProperty(PropertyName = "pathVariables")] 
    public Dictionary<string, string> PathVariables { get; set; } 

    /// <summary> 
    ///  method of request 
    /// </summary> 
    [JsonProperty(PropertyName = "method")] 
    public string Method { get; set; } 

    /// <summary> 
    ///  data to be sent with the request 
    /// </summary> 
    [JsonProperty(PropertyName = "data")] 
    public string Data { get; set; } 

    /// <summary> 
    ///  data mode of reqeust 
    /// </summary> 
    [JsonProperty(PropertyName = "dataMode")] 
    public string DataMode { get; set; } 

    /// <summary> 
    ///  name of request 
    /// </summary> 
    [JsonProperty(PropertyName = "name")] 
    public string Name { get; set; } 

    /// <summary> 
    ///  request description 
    /// </summary> 
    [JsonProperty(PropertyName = "description")] 
    public string Description { get; set; } 

    /// <summary> 
    ///  format of description 
    /// </summary> 
    [JsonProperty(PropertyName = "descriptionFormat")] 
    public string DescriptionFormat { get; set; } 

    /// <summary> 
    ///  time that this request object was generated 
    /// </summary> 
    [JsonProperty(PropertyName = "time")] 
    public long Time { get; set; } 

    /// <summary> 
    ///  version of the request object 
    /// </summary> 
    [JsonProperty(PropertyName = "version")] 
    public string Version { get; set; } 

    /// <summary> 
    ///  request response 
    /// </summary> 
    [JsonProperty(PropertyName = "responses")] 
    public ICollection<string> Responses { get; set; } 

    /// <summary> 
    ///  the id of the collection that the request object belongs to 
    /// </summary> 
    [JsonProperty(PropertyName = "collection-id")] 
    public Guid CollectionId { get; set; } 

    /// <summary> 
    ///  Synching 
    /// </summary> 
    [JsonProperty(PropertyName = "synced")] 
    public bool Synced { get; set; } 
} 

Maintenant, tout ce que vous devez faire est de faire une requête GET à api/postier [d'application] et vous aurez la dernière API reposant sous une forme c'est lisible par un facteur.

+0

D'où provient GetHelpPageSampleGenerator() '? Y a-t-il un paquet NuGet? J'ai trouvé un candidat potentiel [ici] (https://github.com/flextry/Telerik-Academy/tree/master/Programming%20with%20C%23/0.%20Exams/Telerik%202013-2014%20-%20Web % 20Services% 20% 26% 20Cloud/Web% 20Services% 20% 26% 20Cloud% 20-% 20Exam% 20Preparation/ForumSystem.Web/Zones/HelpPage/SampleGeneration). – mason

+0

Correct, j'utilise Microsoft ASP.NET Web API 2.2 Page d'aide https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Help page – rheone

+0

J'ai dû faire un léger changement, je recevais une exception NullReferenceException dans 'PostmanCollectionForController()'. J'ai enlevé ce genre: '.ThenBy (description => description.Documentation.ToString (CultureInfo.InvariantCulture))' – mason

1

Vous devrez également mettre à jour le modèle PostmanRequestGet.cs pour que cela fonctionne.

mise à jour comme suit: -

/// <summary> 
     ///  the id of the collection that the request object belongs to 
     /// </summary> 
     [JsonProperty(PropertyName = "collectionId")] 
     public Guid CollectionId { get; set; } 
+2

Je pense que cela devrait être un commentaire à la réponse à laquelle vous faites référence –

0

Pourquoi ne pas utiliser Swagger standard et l'utiliser avec Postman?

  1. Qu'est-ce que Swagger? (Rest documentation de l'API Web et les clients Enabler)
  2. Importing Swagger files to Postman
  3. Utilisez Swashbuckle package NuGet en studio visuel pour générer Swagger pour votre API (Install-Package Swashbuckle -Pré)

Bonus: Ce solution est pris en charge avec ASP.NET Core Rest WebAPI

+1

Au moment de répondre à la question, même si je peux me tromper, Postman n'a pas lu les fichiers swagger. Bien que j'utilise ceci comme approche actuelle pour l'un de mes plusieurs projets d'API Web développés dans ASP.NET 4.x. Même ainsi, une approche fantaisiste nécessite l'utilisation de bibliothèques supplémentaires avec une licence éventuellement incompatible. De même, l'implémentation de Swashbuckle, même si elle est plus riche en fonctionnalités, ne fournit pas un contrôle aussi fin et précis que la solution mentionnée ci-dessus avec des fonctionnalités spécifiques de Postman qui ne sont pas couvertes par la spécification swagger. – rheone

+0

Pour certains c'est assez bon, donc c'est présent comme une réponse pour les futures références, y compris moi-même. – hB0

Questions connexes