Skip to content

thomasraynal/SwaggerPlayground

Repository files navigation

SwaggerPlayground

Generating Nancy API from swagger specification using BeezUp dotnet-codegen and Handlebars.Net.

This an experimental code generator tool which allow the generation of the backbone of a service based on a swagger specification.

The idea is to generate:

  • The Nancy module (i.e controller) of the service, as an abstract class allowing customization of the route behavior (specifically security issues). It should handle exception mapping with HTTP status code, given the swagger response spec for that route as well as, of course, the response status code.
  • The request DTO with its validator (using FluentValidation), and default validation pattern given the swagger specs, both for the request and for the nested objects, recursively. Each validator being an extendable abstract class.
  • The response DTO (the first 2XX response found on the specification), which usually is a swagger definition, rendered as an extendable partial class.
  • The swagger definition objects, also with their validators, with a special attention given to the inlined object definition (rendered as ValueTuple) and enum.
complexObjectE:
      type: object
      properties:
        pack_type:
          type: string
          enum:
            - nice
            - naughty
            - huge_bonus
            - immortal
            - stocking_killer
        team:
          type: string
          enum: [aog, au, afs, cgs, cpp, egc, fea, hl, sbr, uosp, vt]
        something:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
                type: object
                properties:
                  propA:
                   type: integer
                   format: int64
                  propB:
                   type: object
                   properties:
                      propC:
                        type: integer
                        format: int64
                      propD:
                        type: object
                        additionalProperties:
                            type: object
                            additionalProperties:
                              type: string
                              format: date-time
    public partial class ComplexObjectE
    {
      public Pack_type Pack_type {get; set; }
      public Team Team {get; set; }
      public IEnumerable<(string, IEnumerable<(string, ( long propA , ( long propC , IEnumerable<(string, IEnumerable<(string, DateTime )> )> propD ) propB ))> )> Something {get; set; }
    }
  • The service interface, which, implemented, will send back to the controller the required response.

TL;DR:

swagger: "2.0"
info:
  description: "This is a sample server Petstore server.  You can find out more about Swagger at <a href=\"http://swagger.io\">http://swagger.io</a> or on irc.freenode.net, #swagger.  For this sample, you can use the api key \"special-key\" to test the authorization filters"
  version: 1.0.0
  title: Swagger Petstore YAML
  termsOfService: "http://swagger.io/terms/"
  contact:
    email: "apiteam@swagger.io"
  license:
    name: Apache 2.0
    url: "http://www.apache.org/licenses/LICENSE-2.0.html"
basePath: /v2
x-product: 
    appName: petStoreApp
    appService: petStore
[...]
paths:
  /pet:
    post:
      tags:
        - pet
      summary: Add a new pet to the store
      description: ""
      operationId: addPet
      consumes:
        - application/json
        - application/xml
      produces:
        - application/xml
        - application/json
      parameters:
        - in: body
          name: body
          description: Pet object that needs to be added to the store
          required: true
          schema:
            $ref: "#/definitions/Pet"
      responses:
        "201":
          schema:
             $ref: "#/definitions/Pet"
          description: successful operation
        "400":
          description: Invalid ID supplied
        "405":
          description: Invalid input
[...]
    public interface IPetStoreService
    {
        Task< Pet > AddPet(AddPetRequest request);
     [...]
    }
    public abstract class PetStoreModuleBase : NancyModule
    {
        public PetStoreModuleBase(IPetStoreService petStoreService) : base("/v2")
        {

           Post("/pet",  async (parameters, token) =>
            {
                ConfigureAddPetRequestRoute();

                return await this.EvaluateAndBind<AddPetRequest>(async (request) => await petStoreService.AddPet(request),  HttpStatusCode.Created );
            });
        }
     [...]
     
        protected virtual void ConfigureAddPetRequestRoute()
        {
        }
        
     [...]
    }
    public partial class AddPetRequest
    {
        public Pet Body { get; set; }

        public override bool Equals(object obj)
        {
            return obj is AddPetRequest && obj.GetHashCode() == GetHashCode();
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = nameof(AddPetRequest).GetHashCode();
                if (default != Body) hashCode = (hashCode * 397) ^ Body.GetHashCode();
                return hashCode;
            }
        }
    }


    public class HttpResponseAddPet400Exception : Exception, IHasHttpServiceError
    {
      [...]
    }

    public class HttpResponseAddPet405Exception : Exception, IHasHttpServiceError
    {
      [...]
    }


    public class AddPetRequestValidator : AbstractValidator<AddPetRequest>
    {
        public AddPetRequestValidator()
        {
            RuleFor(request => request.Body).NotNull().WithMessage("Body is required");
        }
    }

}
definitions:
  Pet:
    required:
      - name
      - photoUrls
    properties:
      id:
        type: integer
        format: int64
      category:
        $ref: "#/definitions/Category"
      name:
        type: string
        example: doggie
      photoUrls:
        type: array
        xml:
          name: photoUrl
          wrapped: true
        items:
          type: string
      tags:
        type: array
        xml:
          name: tag
          wrapped: true
        items:
          $ref: "#/definitions/Tag"
      petStatus:
        type: string
        description: pet status in the store
        enum:
          - available
          - pending
          - sold
    xml:
      name: Pet
    public partial class Pet
    {
      public long Id {get; set; }
      public Category Category {get; set; }
      public string Name {get; set; }
      public IEnumerable< string > PhotoUrls {get; set; }
      public IEnumerable<Tag> Tags {get; set; }
      public PetStatus PetStatus {get; set; }

    }

    public abstract class PetValidatorBase : AbstractValidator<Pet>
    {
        public PetValidatorBase()
        {
                        RuleFor(dto => dto.Name).NotNull().NotEmpty().WithMessage("Name is required");
                        RuleFor(dto => dto.PhotoUrls).NotNull().WithMessage("PhotoUrls is required");
        }
    }

About

Nancy + Swagger + Handlebars

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published