Class: Arafa::Whatsapp::AfricasTalking

Inherits:
Object
  • Object
show all
Extended by:
Dry::Initializer
Defined in:
lib/arafa/whatsapp/africas_talking.rb

Overview

Africa's Talking WhatsApp adapter (§1.13). Unlike bulk SMS/airtime/ mobile data, AT's WhatsApp API sends to one recipient per request (phoneNumber is a single string, not an array), so SendResult here always carries exactly one recipient. All five documented message kinds are supported — see Whatsapp::MessageBody.

Constant Summary collapse

CONTRACT =
Contracts::WhatsappContract
BODY_TYPE =
Types.Instance(MessageBody::Text) | Types.Instance(MessageBody::Media) |
Types.Instance(MessageBody::Template) | Types.Instance(MessageBody::Interactive::Buttons) |
Types.Instance(MessageBody::Interactive::List)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.connectionObject

Reuses Providers::Base's connection (retry, JSON, apiKey-redacting logger) rather than building a second one.



64
65
66
# File 'lib/arafa/whatsapp/africas_talking.rb', line 64

def connection
  Providers::Base.connection
end

.send(*args, **kwargs) ⇒ Object



56
57
58
59
60
# File 'lib/arafa/whatsapp/africas_talking.rb', line 56

def send(*args, **kwargs)
  return super if args.any? || kwargs.empty?

  new(**kwargs).send
end

Instance Method Details

#build_payloadObject



103
104
105
# File 'lib/arafa/whatsapp/africas_talking.rb', line 103

def build_payload
  { username: username, waNumber: wa_number, phoneNumber: phone_number, body: body.to_h }
end

#connectionObject



84
85
86
# File 'lib/arafa/whatsapp/africas_talking.rb', line 84

def connection
  self.class.connection
end

#endpointObject



88
89
90
# File 'lib/arafa/whatsapp/africas_talking.rb', line 88

def endpoint
  "https://chat.africastalking.com/whatsapp/message/send"
end

#headersObject

AT's WhatsApp API is the one product that spells this header lowercase (apikey) instead of apiKey.



94
95
96
97
98
99
100
101
# File 'lib/arafa/whatsapp/africas_talking.rb', line 94

def headers
  base = {
    "apikey" => Arafa.config.africas_talking.api_key,
    "Content-Type" => "application/json",
    "Accept" => "application/json"
  }
  idempotency_key.nil? ? base : base.merge("Idempotency-Key" => idempotency_key)
end

#parse_response(response) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/arafa/whatsapp/africas_talking.rb', line 107

def parse_response(response)
  return build_failure(response) unless response.status.between?(200, 299)

  body = response.body
  status = body["status"]
  return Failure(Arafa::InvalidRequestError.new(body["errorMessage"] || body.to_s)) if status.nil?

  build_success(body, status)
end

#send(*args, **kwargs) ⇒ Object

Contract → HTTP call → response parsing. Returns a Dry::Monads::Result: Success(SendResult) or Failure(Arafa::Error subclass).



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/arafa/whatsapp/africas_talking.rb', line 72

def send(*args, **kwargs)
  return super if args.any? || kwargs.any?

  validation = validate_contract
  return validation if validation.failure?

  response = connection.post(endpoint, build_payload, headers)
  parse_response(response)
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
  Failure(Arafa::NetworkError.new(e.message))
end