Humanizer

Neste tutorial iremos criar um microsserviço de customer e utilizaremos a biblioteca Humanizer para registrar a data de cadastro e também definir um campo string com a data no formato ordinal.

Importante

O exemplo a seguir utiliza a biblioteca Humanizer, mas você pode utilizar a biblioteca que desejar, o foco neste momento é o entendimento de como o Devprime habilita o uso de extensões e como integrá-las em seu projeto sem ferir os princípios de arquitetura estabelecidos, garantindo separação de responsabilidades e desacoplamento.

Criando um microserviço para utilizar no exemplo

Nós utilizaremos um microsserviço baseado na plataforma Devprime

Digite o comando abaixo em um diretório de sua preferência e em seguida abra o projeto no Visual Studio, VSCODE ou sua IDE de preferência:
dp new customer --stream rabbitmq --state mongodb

Acesse a pasta raiz do projeto: .\customer\

Implementações de domínio

Nós precisamos incluir um aggregate root para compor as funcionalidades de negócio do nosso contexto, sendo assim, digite o seguinte comando em seu terminal:
dp add aggregate Customer

O CLI deverá criar a classe Customer.cs onde iremos incluir nossas primeiras regras de negócio. Abra o caminho: code .\src\core\domain\aggregates\customer\Customer.cs e inclua as propriedades conforme exemplo abaixo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
namespace Domain.Aggregates.Customer;
public class Customer : AggRoot
{
    public string FullName { get; private set; }
    public string CustomerTaxID { get; private set; }
    public string Address { get; private set; }
    public string Phone { get; private set; }
    public string Email { get; private set; }
    public DateTime CreationDate { get; private set; }
    public string OrdinalCreationDate { get; private set; }

    public void SetOrdinalDate(string ordinalCreationDate)
    {
        OrdinalCreationDate = ordinalCreationDate;
    }
}

Acelerando implementações com o CLI

O próximo passo será utilizar o CLI para acelerar as grande parte das implementações necessárias e para isso digite o comando abaixo em seu terminal:

dp init

O CLI solicita autorização para alterar os arquivos necessários da solution, neste caso vamos digitar A para autorizar todos os arquivos.

Acesse novamente o aggregate root no caminho: code .\src\core\domain\aggregates\customer\Customer.cs e altere o método Add() conforme o exemplo a seguir:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public virtual void Add()
{
    Dp.Pipeline(Execute: () =>
    {
        ID = Guid.NewGuid();
        IsNew = true;
        CreationDate = DateTime.UtcNow;

        ValidFields();
        Dp.ProcessEvent(new CustomerCreated());
    });
}

Ainda no aggregate root altere o método ValidFields() removendo a validação referente ao campo OrdinalCreationDate como mostra o exemplo a seguir:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private void ValidFields()
{
    if (String.IsNullOrWhiteSpace(FullName))
        Dp.Notifications.Add("FullName is required");
    if (String.IsNullOrWhiteSpace(CustomerTaxID))
        Dp.Notifications.Add("CustomerTaxID is required");
    if (String.IsNullOrWhiteSpace(Address))
        Dp.Notifications.Add("Address is required");
    if (String.IsNullOrWhiteSpace(Phone))
        Dp.Notifications.Add("Phone is required");
    if (String.IsNullOrWhiteSpace(Email))
        Dp.Notifications.Add("Email is required");
    if (CreationDate == DateTime.MinValue)
        Dp.Notifications.Add("CreationDate is required");

    Dp.Notifications.ValidateAndThrow();
}

Adicionando uma extension

Nós vamos incluir agora a classe HumanService que será a nossa extension, através do seguinte comando do Devprime CLI.

dp add extensions HumanService

O CLI solicita autorização para alterar os arquivos necessários da solution, tecle A para autorizar todos os arquivos.

A imagem a seguir mostra a classe HumanService e sua Interface IHumanService, cuja responsabilidade será implementar as integrações com a biblioteca Humanizer.

Ela mostra também a classe Extensions e a interface IExtensions cuja finalidade é ser um proxy que permite ao contexto de execução do Devprime Pipeline, acessar todas as extensions disponíveis na aplicação via injeção de dependência.

Devprime How To Extensions Key`

Adicionando a referência para a biblioteca Humanizer

Nós vamos incluir a biblioteca Humanizer em nosso projeto, lembre-se de definir o destino de instalação para o projeto “Devprime.Extensions”. code .\src\adapters\extensions\Devprime.Extensions.csproj

Via dotnet CLI

dotnet add .\src\adapters\extensions\Devprime.Extensions.csproj package Humanizer

Rode também o dotnet build no projeto. (Lembre-se de estar na pasta raíz do projeto .\customer\):

dotnet build

Implementando a integração com a biblioteca Humanizer

Nós vamos alterar a interface “IHumanService” existente no caminho code .\src\core\application\interfaces\adapters\extensions\IHumanService.cs, incluindo a assinatura de método a seguir:

1
string ToOrdinalWords(DateTime date);

Nós também precisamos implementar o método na classe “HumanService” code .\src\adapters\extensions\humanservice\HumanService.cs, deixando-a conforme segue:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using Humanizer;
using System;
namespace Devprime.Extensions.HumanService;
public class HumanService : DevprimeExtensions, IHumanService
{
    public HumanService(IDpExtensions dp) : base(dp)
    {
    }

    public string ToOrdinalWords(DateTime date)
    {
        return Dp.Pipeline(ExecuteResult: () =>
        {
            var result = date.ToOrdinalWords();
            return result;
        });
    }
}

Implementado a chamada ao adapter de extension

O nosso cenário envolve um evento de domínio chamado “CustomerCreated” e associado a ele temos um EventHandler chamado “CustomerCreatedEventHandler”, que possui uma chamada ao Devprime State Adapter para persistência dos dados (linha 11) e emite um evento externo à aplicação (linha 26).
Caminho: code .\src\Core\Application\EventHandlers\Customer\CustomerCreatedEventHandler.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace Application.EventHandlers.Customer;
public class CustomerCreatedEventHandler : EventHandler<CustomerCreated, ICustomerState>
{
    public CustomerCreatedEventHandler(ICustomerState state, IDp dp) : base(state, dp){}

    public override dynamic Handle(CustomerCreated customerCreated)
    {
        var success = false;
        var customer = customerCreated.Get<Domain.Aggregates.Customer.Customer>();
        
        Dp.State.Customer.Add(customer);

        var destination = Dp.Settings.Default("stream.customerevents");
        var eventName = "CustomerCreated";
        var eventData = new CustomerCreatedEventDTO()
        {
            ID = customer.ID,
            FullName = customer.FullName,
            CustomerTaxID = customer.CustomerTaxID,
            Address = customer.Address,
            Phone = customer.Phone,
            Email = customer.Email,
            CreationDate = customer.CreationDate,
            OrdinalCreationDate = customer.OrdinalCreationDate
        };
        Dp.Stream.Send(destination, eventName, eventData);

        success = true;
        return success;
    }
}

Altere o código do nosso EventHandler conforme modelo abaixo (vide linhas destacadas):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace Application.EventHandlers.Customer;
public class CustomerCreatedEventHandler : EventHandlerWithStateAndExtensions<CustomerCreated, ICustomerState, IExtensions>
{
    public CustomerCreatedEventHandler(ICustomerState state, IExtensions extension, IDp dp) : base(state, extension, dp) { }

    public override dynamic Handle(CustomerCreated customerCreated)
    {
        var success = false;
        var customer = customerCreated.Get<Domain.Aggregates.Customer.Customer>();

        var ordinalCreationDate = Dp.Extensions.HumanService.ToOrdinalWords(customer.CreationDate);
        customer.SetOrdinalDate(ordinalCreationDate);

        Dp.State.Customer.Add(customer);

        var destination = Dp.Settings.Default("stream.customerevents");
        var eventName = "CustomerCreated";
        var eventData = new CustomerCreatedEventDTO()
        {
            ID = customer.ID,
            FullName = customer.FullName,
            CustomerTaxID = customer.CustomerTaxID,
            Address = customer.Address,
            Phone = customer.Phone,
            Email = customer.Email,
            CreationDate = customer.CreationDate,
            OrdinalCreationDate = customer.OrdinalCreationDate
        };

        Dp.Stream.Send(destination, eventName, eventData);

        success = true;
        return success;
    }
}

Testando a aplicação

Agora que temos as implementações necessárias, vamos rodar o microsserviço através do comando abaixo:

Windows

.\run.ps1

Linux / Mac

.\run.sh

No browser, acesse o link: https://localhost:5001/swagger, nós vamos utilizar o método POST para criar um novo customer:

Devprime How To Extensions Key`

Utilize o Request Body abaixo:

1
2
3
4
5
6
7
{
  "fullName": "Bot One",
  "customerTaxID": "37429734",
  "address": "Av. Paulista, 1811",
  "phone": "11999999999",
  "email": "botone@bot.com"
}

Ainda na API utilize o endpoint de GET para obter os customers cadastrados (não necessita passar nenhum parâmetro), o resultado do Response Body deve ser similar ao seguinte:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "response": [
    {
      "id": "997809ad-e48f-4eb4-9145-4b569adba492",
      "fullName": "Bot One",
      "customerTaxID": "37429734",
      "address": "Av. Paulista, 1811",
      "phone": "11999999999",
      "email": "botone@bot.com",
      "creationDate": "2022-04-05T03:28:47.16Z",
      "ordinalCreationDate": "April 5th, 2022" //Humanized by our extension
    }
  ],
  "total": 1,
  "pageTotal": 1,
  "hasNext": false,
  "hasPrevious": false,
  "success": true
}

Mais artigos sobre extensions

SendGrid

Última modificação October 26, 2023 (795e8af6)