Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sugestão] Adicionar tipagem e validação de dados nos métodos da SDK #8

Open
DenisBessa opened this issue Dec 27, 2022 · 2 comments

Comments

@DenisBessa
Copy link

Uma sugestão que melhoraria muito a SDK: adicionar tipos aos métodos, de modo que o desenvolvedor saiba quais valores são aceitos para cada parâmetro da SDK e quais valores a API vai retornar. Isso melhoria muito a DevX, porque o desenvolvedor não precisaria ficar lendo a documentação pra saber quai(s) campos são obrigatórios, e o próprio ambiente de desenvolvimento pode retornar se o objeto estiver incompleto ou inválido, por exemplo.

Estou falando de algo mais ou menos assim:

type BolixCreate = {
    payment: {
        banking_billet: {
            message?: string | undefined;
            configurations?: {
                fine: number;
                interest: number;
            } | undefined;
            expire_at: string;
            customer: {
                name: string | null;
                juridical_person: {
                    ...;
                };
                cpf: string | null;
                email: string;
                phone_number: string;
                address: {
                    ...;
                };
            };
        };
    };
    items: {
        ...;
    }[];
}

Daí a SDK poderia exigir este tipo no parâmetro body dos método que cria o Bolix, por exemplo.

Uma outra abordagem, mais sofisticada, seria adicionar uma biblioteca de validação de dados à SDK, como por exemplo o Zod.

Isso permitiria ao aplicativo validar os dados em tempo de execução, antes do envio para a Gerencianet. Desta forma, por exemplo, caso o usuário insira um CNPJ inválido, a própria SDK validaria este campo, sem necessidade de enviar os dados inválidos para a API só pra receber uma resposta de erro.

O Zod permite a validação de tipos em runtime, o que estende a segurança de tipo da aplicação, já que o Typescript faz a validação somente em build time.

Eu mesmo montei a validação "por tentativa e erro" aqui, mas sinto que está incompleto. Se a SDK fizesse isso, seria bem legal.

export const BolixCreateSchema = z.object({
  items: z.array(
    z.object({
      name: z.string().max(255),
      value: z.number().int().min(500),
      amount: z.number().int(),
    })
  ),
  payment: z.object({
    banking_billet: z.object({
      customer: z.object({
        juridical_person: z.object({
          corporate_name: z.string().max(255),
          cnpj: z.string().refine((s) => isCNPJ(s), { message: "CNPJ inválido" }),
        }),
        name: z.string().max(255).nullable(),
        cpf: z
          .string()
          .refine((s) => isCPF(s), { message: "CPF inválido" })
          .nullable(),
        email: z.string().email(),
        phone_number: z.string(),
        address: z.object({
          street: z.string(),
          number: z.string(),
          neighborhood: z.string(),
          zipcode: z.string(),
          city: z.string(),
          complement: z.string(),
          state: z.string(),
        }),
      }),
      expire_at: commonDateToString.refine((s) => moment(s).isAfter(moment()), { message: "Data de vencimento deve ser após a data atual" }),
      configurations: z
        .object({
          fine: z.number(),
          interest: z.number(),
        })
        .optional(),
      message: z.string().optional(),
    }),
  }),
});

Caso os mantenedores gostem da ideia, eu mesmo posso fazer uma PR implementando as sugestões.

@brunodmn
Copy link

brunodmn commented Jul 5, 2023

Estou usando com nestjs e nem os métodos estão aparecendo quando crio a instância...não faz sentido fazer uma lib em typescript e não ser type safe.
Deveria fazer direito, ou remover e manter apenas a lib node, que isso é propaganda enganosa.

@DenisBessa
Copy link
Author

Já passei por isso, tá aí:

Schema do zod para notificações via webhook:

const BolixNotifications = z.object({
  status: z.string(),
  data: z.array(
    z.object({
      id: z.number(),
      type: z.string(),
      custom_id: z.null(),
      status: z.object({ current: z.string(), previous: z.string().nullable() }),
      identifiers: z.object({ charge_id: z.number() }),
      created_at: z.string(),
    })
  ),
});

E para a API do bolix:

export const BolixCreateSchema = z.object({
  items: z.array(
    z.object({
      name: z.string().max(255, { message: "Deve ter no máximo 255 caracteres" }),
      tempValue: z.number(),
      value: z.number().int().min(500, { message: "Deve ser no mínimo R$ 5,00" }),
      amount: z.number().int().min(1, { message: "Deve ser no mínimo 1" }),
    })
  ),
  payment: z.object({
    banking_billet: z.object({
      customer: z.object({
        juridical_person: z.object({
          corporate_name: z.string().max(255, { message: "Deve ter no máximo 255 caracteres" }).optional(),
          cnpj: z
            .string()
            .refine((s) => isCNPJ(s), { message: "CNPJ inválido" })
            .optional(),
        }),
        name: z.string().max(255).optional(),
        cpf: z
          .string()
          .refine((s) => isCPF(s), { message: "CPF inválido" })
          .optional(),
        email: z.string().email(),

        // this format: .
        phone_number: z.string().regex(/^[1-9]{2}9?[0-9]{8}$/, { message: "Telefone inválido" }),
        address: z.object({
          street: z.string(),
          number: z.string(),
          neighborhood: z.string(),
          zipcode: z.string().refine((s) => isCEP(s), { message: "CEP inválido" }),
          city: z.string(),
          complement: z.string().optional(),
          state: z.string(),
        }),
      }),
      expire_at: z.string().refine((s) => dayjs(s, "YYYY-MM-DD").isAfter(dayjs()), { message: "Deve ser após a data atual" }),
      configurations: z
        .object({
          fine: z.number(),
          interest: z.number(),
        })
        .optional(),
      message: z.string().optional(),
    }),
  }),
  metadata: z.object({
    notification_url: z.literal("[sua url]"),
  }),
  tempCpfCnpj: z.string().refine((s) => isCPFOrCNPJ(s), { message: "CPF/CNPJ inválido" }),
  tempName: z.string().max(255, { message: "Deve ter no máximo 255 caracteres" }),
  tempExpireAt: z.string().refine((s) => dayjs(s, "DD/MM/YYYY").isAfter(dayjs()), { message: "Deve ser após a data atual" }),
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants