APIs e Microsserviços

1 nov, 2016

API Rest com Workflow ASync e MassTransit

Publicidade

Quando se fala em arquitetura de microsserviços, logo a divisão de responsabilidade e domínio de cada processo/aplicação se torna extremamente relevante e importante. Sendo assim, serviços baseados em eventos e/ou transporte via barramento de dados tornam-se viáveis, e são também grandes aliados dessa arquitetura, garantindo o desacoplamento necessário e a interoperabilidade entre sistemas.

RabbitMQ Message Broker

Por muitas vezes, o feedback de equipes de desenvolvimento que trabalham com RabbitMQ denota uma grande dificuldade e complexidade na operação de integração com a ferramenta quando utilizada a SDK C# .Net padrão, RabbitMQ Client, fornecida pelo time de desenvolvimento da própria RabbitMQ. Isso ocorre por ser necessário trabalhar diretamente com serialização de objetos em buffer de bytes, controle de fluxo de dados mais detalhados e uma quantidade grande de itens de configuração que podem impactar na produtividade e na qualidade do sistema desenvolvido.

MassTransit .Net Service Bus Framework

É interessante, principalmente quando se projeta uma arquitetura utilizando serviços de barramento, ter controle total do fluxo de dados. No entanto, isso não pode se tornar uma tarefa complexa e dispendiosa que gere impacto nas entregas.

O MassTransit é uma ótima opção para minimizar esse impacto e, ao mesmo tempo, ter controle total do fluxo de dados, acesso às configurações avançadas na implementação de componentes e camadas de integração com RabbitMQ Message Boker.

O MassTransit é um framework open source para aplicações distribuídas que torna simples, rápida e escalável essa tarefa de integração. Dados e informações adicionais do framework podem ser encontrados em:

Integrações com MassTransit

O MassTransi framework oferece uma lista considerável de integrações e componentes, que minimiza ainda mais a carga de trabalho e a complexidade no desenvolvimento. Além do RabbitMQ, é possível conectar com o AzureServicebus.

Sua vasta biblioteca possui componentes para Log4Net/NLog, MongoDB, Autofac, CastleWindsor, Microsoft Unity, Ninject, NHibernate, StructMap, Quartz, Entiti Framework, entre outros. Veja a lista completa em: https://www.nuget.org/packages?q=masstransit

Web API ASync

Para exemplificar o uso do MassTransit com RabbitMQ Message Broker, será abordada uma Web API REST com fluxo assíncrono, ou seja, a API, ao receber a requisição, irá disponibilizar os dados na fila para processamento e irá retornar para o cliente a seguinte informação: “Solicitação recebida com sucesso, dados em processamento”.

O consumidor irá obter a informação da fila e efetuará o processamento em segundo plano, sem que seja necessário travar o cliente que efetuou a requisição na API.

Figura 1 – Fluxo de mensagens da API Rest com workflow assíncrono
Figura 1 – Fluxo de mensagens da API Rest com workflow assíncrono

Laboratório – API Rest

Neste exemplo, iremos utilizar as seguintes tecnologias:

  • C# .Net Web.API 2.0
  • RabbitMQ 3.6.0
  • MasTransit Framework 3.0

Crie um novo projeto We.API 2.0 e instale o framework do MassTransit. Em seguida, execute o seguinte comando no console do NuGet Package Console:

  • Install-Package MassTransit.RabbitMQ

Crie uma nova Controller chamada Sale para simular um processo de solicitação de autorização de compra com cartão de crédito. E duas entidades – para recepção (CreateTransactionRequest) e resposta (CreateTransactionResponse) do processamento.

Listagem 1 – CreateTransactionRequest

    // Requisição de criação de transação de cartão de crédito
    public class CreateTransactionRequest {

        [Required]
        public string CreditCardNumber { get; set; } // Número do cartão

        [Required]
        public string SecurityCode { get; set; } // Código de segurança

        [Required]
        public string ExpMonth { get; set; } // Mês de expiração

        [Required]
        public string ExpYear { get; set; } // Ano de expiração

        [Required]
        public string HolderName { get; set; } // Nome do comprador
        
 [Required]
        public long AmountInCents { get; set; } // Valor em centavos

        public Guid TransactionKey { get; set; } // Chave da transação

        public Guid RequestKey { get; set; } // Chave da requisição

        public CreateTransactionRequest()        {
            this.TransactionKey = Guid.NewGuid();//Cria a chave da transação
            this.RequestKey = Guid.NewGuid(); //Cria a chave de requisição
        }
    }

Listagem 2 – CreateTransactionResponse

    // Resposta da criação de transação
    public class CreateTransactionResponse {
        public Guid TransactionKey { get; set; }
        public dynamic Errors { get; set; }
    }

Listagem 3 – Web.API Controller

   /// <summary>
    /// Controlador dos recursos de venda
    /// </summary>
    [RoutePrefix("api")]
    public class SaleController : ApiController {

        /// <summary>
        /// Cria uma venda
        /// </summary>
        /// <param name="createTransactionRequest">Dados da requisição</param>
        /// <returns>Retorna uma venda</returns>
        [HttpPost]
        [Route("sale/")]
        public IHttpActionResult CreateSale(CreateTransactionRequest createTransactionRequest) {
            try {
                //Verifica se há erros
                if (!ModelState.IsValid) {
                    var message = string.Join(" | ", ModelState.Values
                        .SelectMany(v => v.Errors)
                        .Select(e => e.ErrorMessage));
                    //Retorna a lista de erros
                    return BadRequest(message);
                }

                //Conecta no barramento de servios
                var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
                {
                    var host = sbc.Host(new Uri("rabbitmq://localhost/"), h =>
                    {
                        h.Username("guest");
                        h.Password("guest");
                    });
                });
                //Inicia o barramento
                using (bus.Start()) {
                    var task = bus.Publish<CreateTransactionRequest>(createTransactionRequest);
                    task.Wait();
                }

                //Cria a resposta
                var createSaleResponse = new CreateTransactionResponse() {
                    TransactionKey = createTransactionRequest.TransactionKey
                };
                return Ok(createSaleResponse);
            } catch (Exception ex) {
                return InternalServerError(ex);
            }
        }
    }

Laboratório – Consumindo dados do barramento

Neste exemplo, iremos utilizar as seguintes tecnologias:

  • Application console, que também poderá ser convertida em Windows Service ou WebJob posteriormente
  • RabbitMQ 3.6.0
  • MasTransit Framework 3.0

Crie um novo projeto Console Application e instale o framework do MassTransit. Execute o seguinte comando no console do NuGet Package Console:

  • Install-Package MassTransit.RabbitMQ

Na classe principal, defina a seguinte listagem de código:

Listagem 4 – Aplicação de recepção de dados do barramento

        static void Main(string[] args) {
            //Acessa o barramento e efetua a conexão
            var bus = Bus.Factory.CreateUsingRabbitMq(sbc => {
                var host = sbc.Host(new Uri("rabbitmq://localhost/"), h => {
                    h.Username("guest");
                    h.Password("guest");
                });

                //Conecta no barramento e aguarda o evento de recpção
                sbc.ReceiveEndpoint(host, "InputCreateTransactionRequestQueue", endpoint => {
                    endpoint.Handler<CreateTransactionRequest>(async context => {
                        var data = JsonConvert.SerializeObject(context.Message);
                        await Console.Out.WriteLineAsync(quot;Received: {data}");
                    });
                });
            });
	     bus.Start(); //Incia o barramento
            Console.ReadKey(); //Aguarda uma tecla ser pressionada
            bus.Stop(); //Para o barramento
        }

Laboratório – Dados para testes

Para os testes de integração, utilizei o PostMan para enviar a requisição POST com os seguintes parâmetros:

url: http://127.0.0.1:37311/api/sale (porta do IIS Express 37311)

Request Type: POST

Body: {
"CreditCardNumber": "11212",
"SecurityCode" : "3434",
"ExpMonth" : "12",
"ExpYear": "2016",
"HolderName" : "Alexandre",
"AmountInCents": 113 }

 

Link para download do Postman: https://www.getpostman.com/

Conclusão

Com o uso do MassTransit, a tarefa de integração com Message Brokers, como RabbitMq e Azure ServiceBus, torna-se simples e, ainda assim, todo o poder e o controle ainda estão em suas mãos. Desacople seu Workflow com MassTransit, e ganhe performance e produtividade.