Thursday, 4 April 2019

apidoc vs swagger for node app

While developing node services, we might need to expose our Api documents based on requirement. In that case we think of picking right documentation tool because there are many 3rd parties tools available for it. I have created sample POC by using 2 popular documentation tools
a. Swagger and
b. Apidocjs

Here is my finding regarding both:

  • Popularity: By comparing stats,  swagger-ui is more popular then apidocjs.
  • Consistency: If we already using swagger for our Dotnetcore service, then implementing swagger tool will consist more from Info and UI prospective.
  • Implementation complexity: apidocjs and swagger both required documentation content on implemented method as customize comment data. In addition they allow to write documentation data in separate resource file as .js and .json. If we already have swagger.json created by DotnetCore we can reuse more than 80% specification.
  •  Maintenance: For apidocjs will have to modify documentation for each affected method/endpoints if service changed. In swagger we can limit changes. But by implementing apidocjs we can isolate the layer.
  • Other benefits: Because swagger use plain .json that could be parsed through programing language, thus we can get advantage of various other 3rd parties in order to create http client and more. 
  • Future: Due to popularity of swagger, apidocjs provide information about apidoc-swagger converter so we can switch apidoc to swagger anytime.

Steps of using Swagger in to node app

1. Install following packages in your node app by running cmd commands:
npm install swagger-ui-express --save-dev
npm install window --save-dev

2. Add following snippet in app.ts
app.use('/images', express.static(__dirname + '/Images'));

//Use Swagger documentation
const Window = require('window');
var swaggerUi = require('swagger-ui-express'),
    swaggerDocument = require('./src/app/swagger');//When swagger.json available in app

const { document } = new Window();
var swaggerUi = require('swagger-ui-express');
const swaggerOption = {
    customCss: `.swagger-ui .topbar {
              background-color: #007298;
              }
              .topbar-wrapper span {
              visibility: hidden;
              }
              .topbar-wrapper img {
              content: url('../images/logo.png');
              width: 100px;
              height: 30px;
              }`,
    //swaggerUrl: '//www.dotnetapi.com/v1/swagger.json'), // When we need to add json from URL
    swaggerOptions: {
        defaultModelExpandDepth: 0,
        defaultModelsExpandDepth: -1,
        supportedSubmitMethods: ["patch"],
        validatorUrl: null,
        defaultModelRendering: [],
        deepLinking: false,
        onComplete: function (swaggerApi, swaggerUi) {
            document.title = 'Api Docs';
        },
    }
};
app.use('/api_docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOption));

Monday, 4 March 2019

How to increase Unit Test code coverage in DotNetCore?

Hey let me tell you, if you are analyzing unit test coverage in Visual Studio and the scores is not good, this post is for you. Here I will tell you how to analyze the code coverage in visual studio?

First of all you would require Visual Studio Enterprise or else you can try Visual Studio 2019 Preview. In Visual studio Professional code coverage option not given.

Write some code and create unit test and verify it through
Test > Window > Test Explorer or try shortcut (Ctrl+E, T)

In the same Test tab you could find the Analyze Code Coverage Option.



After clicking on it you get complete code coverage details.
Now If you see your coverage score is poor, even if you have written unit test for you projects, don't worry. You project might include some core component or utility that you don't want to comes in coverage. Might be there are many private methods been declared that you want to exclude or some time you have also declared some constructor that you want to exclude.

I would recommend you to use [ExcludeFromCodeCoverageAttribute] attribute  that comes under
Namespace System.Diagnostics.CodeAnalysis, under the Assembly System.Diagnostics.Tools. You can
Apply this attribute on methods or on class to exclude.

If you want to test your private methods then you can try [Unit Testing for Private Methods in DotNet C#]

Some time you also need to refactor the code in such a way that code coverage will increase like:
Avoid return in mid of the implementation.





Wednesday, 13 February 2019

DotnetCore Web API model validation message from resource file.

It's so simple you just need to add resource file ValidationMessage.resx under the project as I have added. After adding it you will found that corresponding ValidationMessage.Designer.resx is not available inside resource folder.


So you need to set Custom Tool property for the .resx file as ResXFileCodeGenerator, as soon as we add it, will find ValidationMessage.Designer.resx.


After enabling it and writing appropriate model with validation attribute with ErrorMessageResourceName = "Password", ErrorMessageResourceType = typeof(ValidationMessage) you may found your required 
ModelValidationState Error message from your resource file.


using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using CoreApp.WebApi.Resources;
 
namespace CoreApp.WebApi.Models
{
    public class UserLogin
    {
        [DisplayName("LoginId")]
        public int UserId { getset; }
 
        [Required(ErrorMessageResourceName = "Password", ErrorMessageResourceType = typeof(ValidationMessage)), MinLength(4), MaxLength(10)]
        public string Password { getset; }
        public DateTime? RequestTime { getset; }
 
    }
}



Note:
Personally I fall in a situation in which I was using services.AddMvcCore() and with this model validation with  DataAnnotations was not working. So after searching out found that we need to use
services.AddDataAnnotations() Extensions in order to enable DataAnnotaions validation. And that worked for DotNetCore Web API model validations.

services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonFormatters()
.AddDataAnnotations()
.AddXmlSerializerFormatters();

Thursday, 7 February 2019

Custom Model Validation Response Globally in DotNetCore

We can validate model globally and can can have custom response globally by using ActionFilter where we can just validate context.ModelState.IsValid or not and based on that we can have custom response there. The advantage of using this filter is that we can set it for few controllers where as if we looking for to apply globally for each controller in dotnet core, now we can change the ApiBehavior using ApiBehaviorOptions. The below code is for creation for extension of IServiceCollection and then simple use inside ConfigureServices();

services.UseCoreAppCustomModelValidation();

Extension:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
 
namespace CoreApp.ModelStateValidation
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection UseCoreAppCustomModelValidation(this IServiceCollection services)
        {
            _ = services.Configure((Action<ApiBehaviorOptions>)(apiBehaviorOptions =>
                    apiBehaviorOptions.InvalidModelStateResponseFactory = actionContext =>
                    {
                        var message = GetModelStateErrorWithException(actionContext);
 
                        return new BadRequestObjectResult(new
                        {
                            Code = 400,
                            Status = 0,
                            Messages = message
                        });
                    }));
            return services;
        }
 
        private static ExpandoObject GetModelStateFriendlyError(ActionContext actionContext)
        {
            var modelType = actionContext.ActionDescriptor.Parameters.FirstOrDefault()?.ParameterType; //Get model type  
                                                                                                       //p => p.BindingInfo.BindingSource.Id.Equals("Body", StringComparison.InvariantCultureIgnoreCase)
 
            var expandoObj = new ExpandoObject();
            var expandoObjCollection = (ICollection<KeyValuePair<stringobject>>)expandoObj//Cannot convert IEnumrable to ExpandoObject  
 
            var dictionary = actionContext.ModelState.ToDictionary(k => k.Key, v => v.Value)
                .Where(v => v.Value.ValidationState == ModelValidationState.Invalid)
                .ToDictionary(
                k =>
                {
                    if (modelType != null)
                    {
                        var property = modelType.GetProperties().FirstOrDefault(p => p.Name.Equals(k.Key, StringComparison.InvariantCultureIgnoreCase));
                        if (property != null)
                        {
                            //Try to get the attribute  
                            var displayName = property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault()?.DisplayName;
                            return displayName ?? property.Name;
                        }
                    }
                    return k.Key; //Nothing found, return original validation key  
                },
                v => v.Value.Errors.Select(e => e.ErrorMessage).ToList() as object); //Box String collection
 
            foreach (var keyValuePair in dictionary)
            {
                expandoObjCollection.Add(keyValuePair);
            }
 
            return expandoObj;
        }
 
        private static List<stringGetModelStateErrorWithException(ActionContext actionContext)
        {
            List<stringerrorMessages = new List<string>();
            foreach (var error in actionContext.ModelState)
            {
                string message = error.Value.Errors != null && error.Value.Errors.Count() > 0 ?
                                    error.Value.Errors[0].Exception != null ?
                                            error.Key + " : " + error.Value.Errors[0].Exception.Message   //More weight-age is given to exception, so in case of one, use the exception message
                                    : error.Value.Errors[0].ErrorMessage != null ?
                                            error.Key + " : " + error.Value.Errors[0].ErrorMessage //Otherwise use error message
                                    : string.Empty
                            : string.Empty;
 
                if (!string.IsNullOrWhiteSpace(message))
                {
                    errorMessages.Add(message);
                }
            }
            return errorMessages;
        }
 
        private static List<stringGetModelStateError(ActionContext actionContext)
        {
            return actionContext.ModelState.Values.SelectMany(x => x.Errors)
                            .Select(x => x.ErrorMessage).ToList();
        }
    }
}

Monday, 4 February 2019

Express module in React.Js

How to install modules in Node.Js?
Either through wizard or from package.json we can add wanted modules in node.js project. I have done it through wizard and you may get reflation in package.json.




Package.json
"devDependencies": {
    "@types/node""^8.0.14",
    "express""^4.16.4"
  }


What is Express modules in Node.Js?
It use connect middle-ware that interact with core http module. So either we work with http module or can have express module in application that help us to configure endpoint, route and more rapidly. More about express could be found here .


How to use express module in node.js?
We just need to add module in project and then can call it in anywhere, like I have use in server.ts.

//load installed module 'express'.
var express = require('express');
 
//initialized express and stored in a variable app.
var app = express();
 
//Created a key having name 'port' with default process value.
app.set('port', process.env.PORT || 1337);
 
 
//Created rout for root '/'
app.get('/'function (req, res) {
    res.send('<html><body><h1>Hello World</h1></body></html>');
});
 
 
 
//Created rout for root '/about'
app.get('/about'function (req, res) {
    res.send('<html><body>My name is raj.</body></html>');
});
 
 
//We can have different verbs like get, post, delete and more.
app.post('/postdata'function (req, res) {
    res.send('POST Request');
});
 
app.put('/updatedata'function (req, res) {
    res.send('PUT Request');
});
 
 
app.delete('/deletedata'function (req, res) {
    res.send('DELETE Request');
});
 
//Again instead of http.createServer module we use app.listen to configure endpoint of App.
var server = app.listen(app.get('port'), function () {
    console.log('Node server is running..');
});



Output in browser:
For root '/'


And for '/about'




Create empty ReactJs Application in Visual Studio

Make sure you have Node.Js component installed for Visual Studio

How to verify Node.Js installed for Visual Studio or not?
Go to Windows > Visual Studio Installer > Modify > Verify Node.Js development




Just few clicks now and your first VS React Application is ready with initial template.


Server.ts
Vital gateway of project that allow us to configure listening port and end point for the project. It is typescript file having extension .ts. Let's have look on each line with comment.

//common es6 syntax to load object(http) from installed module(http).
import http = require('http');

//define port, default port for Node.Js project is 1337 that we can change.
var port = process.env.port || 1337;

//A method of http that we use to create server instance for project. Each request/response will be coming/server through (req,res)
http.createServer(function (req, res) {
    // set response header
    res.writeHead(200, { 'Content-Type''text/html' });
    // set response content    
    res.write('<html><body><h1>Hello World</h1></body></html>');
    res.end();
}).listen(port);

Output



Notes:

Details es6 syntax could be found here
https://codeburst.io/es6-tutorial-for-beginners-5f3c4e7960be
https://www.tutorialspoint.com/es6/es6_syntax.htm

Mode Core module like (http, url, path, fs, util and querystring) could be found here
https://www.tutorialsteacher.com/nodejs/nodejs-modules

Starting with React.Js

Node.Js: Is an open-source server side run-time environment that allow to run JavaScript code on server. Details info could be found here.
Official: https://nodejs.org
W3school: https://www.w3schools.com/nodejs/default.asp


React.Js: Is a client end library written by Facebook that allow us to develop app. It use NodeJs platform to work on both client and server end.

ReactJs Environment Setup
Software: Node.Js run-time, can be found here  
After installation of given component we can verify available version by using following command on CMD.

 node -v
or
 node --version




Test HelloWorld js
Create a file with simple console message.



Now open CMD with located file and run following command it will bring the output on CMD itself.
node main.js