9

Postman è uno strumento che può essere utilizzato per testare facilmente servizi Web riposanti.Come generare raccolte postman JSON da un progetto WebApi2 utilizzando le pagine di assistenza WebApi che sono adatte all'importazione

Se un progetto Asp.Net utilizza WebApi in combinazione con WebApi Helppages, la documentazione può essere generata automaticamente per i servizi Web protetti esposti.

Questa documentazione generata automaticamente è buona, ma potrebbe essere migliorata grazie all'accessibilità aggiuntiva.

Come è possibile combinare queste tecnologie tecnologiche per generare un file JSON che può essere importato in Postman?

risposta

13

Espansione sul post del blog "Using ApiExplorer to export API information to PostMan, a Chrome extension for testing Web APIs" è possibile generare un file JSON che può essere importato in Postman per l'utilizzo in testing e documentazione.

Prima di tutto bisogna controller di configurazione aa in grado di esportare 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())); 
    } 
} 

e generare i modelli adeguati:

Uno per il 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; } 
} 

Uno per il 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; } 
} 

Infine un modello per il 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; } 
} 

Ora tutto quello che dovete fare è effettuare una richiesta GET per [applicazione] api/postino e potrai avere l'ultima API riposante in una forma che è leggibile dal postino.

+0

Da dove proviene 'GetHelpPageSampleGenerator()'? Esiste un pacchetto NuGet? Ho trovato un potenziale candidato [qui] (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/aree/helppage/SampleGeneration). – mason

+0

Corretto, sto usando la pagina di aiuto di Microsoft ASP.NET Web API 2.2 https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Help page – rheone

+0

Ho dovuto apportare una leggera modifica, stavo ottenendo una NullReferenceException in 'PostmanCollectionForController()'. Ho rimosso questo tipo: '.ThenBy (description => description.Documentation.ToString (CultureInfo.InvariantCulture))' – mason

1

Sarà inoltre necessario aggiornare il modello PostmanRequestGet.cs per farlo funzionare.

aggiornamento come segue: -

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

penso che questo dovrebbe essere un commento alla risposta che stai riferendo a –

0

Perché non utilizzare Swagger standard ed usarlo con Postman?

  1. Che cosa è Swagger? (Resto documentazione delle API Web e client enabler)
  2. Importing Swagger files to Postman
  3. Usa Swashbuckle pacchetto NuGet in Visual Studio per generare Swagger per la vostra API (Install-Package Swashbuckle -Pre)

Bonus: Questo è solution supportato con ASP.NET Core Rest WebAPI

+1

Al momento di rispondere alla domanda, anche se potrei sbagliarmi, Postman non ha letto i file swagger. Anche se io uso questo come il mio attuale approccio per uno dei miei numerosi progetti API Web sviluppati in ASP.NET 4.x. Anche se un approccio spavaldo richiede l'uso di librerie aggiuntive con licenza eventualmente incompatibile. Allo stesso modo, l'implementazione di Swashbuckle, anche se può essere più funzionale dal punto di vista estetico, non fornisce un controllo a grana fine/di basso livello come la soluzione menzionata sopra con le caratteristiche specifiche di Postman che non sono incluse nelle specifiche swagger. – rheone

+0

Per alcuni è abbastanza buono, quindi è presente come una risposta per riferimenti futuri tra cui me stesso. – hB0

Problemi correlati