Skip to content

Provider customizado

Criando um provider do zero estendendo a classe base Provider.

Estrutura básica

typescript
import {
  Provider,
  registerProvider,
  createSender,
  SendMessageDto,
  SendMessageResponse,
  ProviderConfig,
  ConfigurationError,
  ValidationError,
} from "@jcsolutions/sender";

// 1. Estender a classe Provider
class MeuProvider extends Provider {
  protected readonly providerName = "meuprovider";
  private readonly from: string;

  constructor(config: ProviderConfig) {
    super(config);
    
    if (!config.from) {
      throw new ConfigurationError("MeuProvider: from é obrigatório");
    }
    this.from = config.from;
  }

  // 2. Sobrescrever headers (se necessário)
  protected buildHeaders(): HeadersInit {
    return {
      "Content-Type": "application/json",
      "X-API-Key": this.token,  // autenticação personalizada
    };
  }

  // 3. Implementar o método send (obrigatório)
  async send(data: SendMessageDto): Promise<SendMessageResponse> {
    if (!this.validatePhone(data.to)) {
      throw new ValidationError("Número inválido");
    }

    const body = {
      to: this.normalizePhone(data.to),
      from: this.from,
      text: data.message,
    };

    const response = await this.request("/send", body);
    const result = await response.json();

    if (!response.ok) {
      this.handleErrorResponse(response.status, result?.message);
    }

    return {
      success: true,
      provider: this.providerName,
      messageId: this.extractMessageId(result),
      raw: result,
    };
  }
}

Registrar o provider

typescript
// Registrar
registerProvider("meuprovider", MeuProvider);

Usar o provider

typescript
const sms = await createSender("meuprovider", {
  token: "minha-api-key",
  baseUrl: "https://api.meuprovider.com/v1",
  from: "MEUAPP",
});

const result = await sms.send({
  to: "923000000",
  message: "Enviado via provider customizado!",
});

Métodos que podem ser sobrescritos

MétodoDescriçãoQuando sobrescrever
buildHeaders()Constrói headers da requisiçãoAutenticação diferente
normalizePhone()Normaliza número de telefoneFormato específico
validatePhone()Valida númeroRegras diferentes
request()Faz requisição HTTPComportamento customizado
handleErrorResponse()Trata erros da APICódigos de erro diferentes
extractMessageId()Extrai ID da respostaCampo do ID diferente
sendBatch()Envio em loteProvider tem batch nativo

Exemplo mínimo

typescript
class ProviderMinimo extends Provider {
  protected readonly providerName = "minimo";

  async send(data: SendMessageDto): Promise<SendMessageResponse> {
    // Implementação mínima
    return {
      success: true,
      provider: this.providerName,
      messageId: "123",
    };
  }
}

Provider com batch nativo

typescript
class MeuProviderComBatch extends Provider {
  protected readonly providerName = "meuprovider";

  async send(data: SendMessageDto): Promise<SendMessageResponse> {
    // implementação...
  }

  // Sobrescrever sendBatch para usar batch nativo
  async sendBatch(data: SendBatchMessageDto): Promise<SendBatchMessageResponse> {
    const { valid, invalid } = this.validatePhones(data.to);
    
    const body = {
      to: this.normalizePhones(valid).join(','),
      message: data.message,
    };

    const response = await this.request("/batch", body);
    const result = await response.json();

    // processar resposta...
  }
}

Dicas importantes

DicaDescrição
providerNameObrigatório declarar protected readonly providerName
ValidaçãoValide configurações específicas no construtor
ErrosUse ConfigurationError, ValidationError, etc
TimeoutO método request() já implementa timeout
BatchA classe base já fornece implementação base

Próximo exemplo

MIT License