twilio / twilio-java

A Java library for communicating with the Twilio REST API and generating TwiML.
MIT License
490 stars 429 forks source link

Change Twilio host to allow integration with MockServer #630

Closed DarknessRdg closed 3 years ago

DarknessRdg commented 3 years ago

Issue Summary

So, this is my scenery: I'm using mockserver on my tests and I need to change twilio host so I can also use mockrserver with twilio. It means I need to change https://api.twilio.com for another host such as http://127.0.0.1 .

Nowadays, the only API I'm using is to send SMS messages, with MessageCreator. I have looked into the code, and it seems the host is places as hardcode when a new Resquest instanciated.

public Request(
        final HttpMethod method,
        final String domain,
        final String uri,
        final String region
    ) {
        this.method = method;
        this.url = "https://" + domain + ".twilio.com" + uri;
        this.region = region;
        this.queryParams = new HashMap<>();
        this.postParams = new HashMap<>();
        this.headerParams = new HashMap<>();
    }

Does anyone know how to change it or even if is possible to change this host using SMS API ?

Steps to Reproduce

  1. Add mockerver to your code dependency (tutorial here)
  2. Implement a functionality with a code looking like the one bellow
    
    // kotlin code
    Twilio.init(twilioAccountSid, twilioAuthToken)

val from = PhoneNumber(twilioPhoneNumber) val to = PhoneNumber(phoneNumber.phone) Message.creator(to, from, "Hello World").create()


3. Try to implement a new test without mocker `MessageCreator` but configure `mockerserver` to return a custom Response data when match the endpoint `2010-04-01/Accounts/{{  twilio_account_sid }}/Messages.json`

### Technical details:
* twilio-java version: 8.9.0
* java version: openjdk version "1.8.0_282"
thinkingserious commented 3 years ago

Hello @DarknessRdg,

How about using this version of the Request function or use a custom HTTP client?

With best regards,

Elmer

DarknessRdg commented 3 years ago

I can't use Request constructor because I would need to implement my own MessageCreator in order to use that constructor.

I could solve my problem using your approach of a custom HTTP client. My solution was to ininherit NetworkHttpClient and override makeRequest to replace the Request URL to a new URL with my custom domain.

class CustomDomainNetworkHttpClient(domain: String) : NetworkHttpClient() {
    private val domain: String

    init {
        val http = Regex("http[s]?://")
        this.domain = if (domain.contains(http)) domain else "http://$domain"
    }

    override fun reliableRequest(request: Request?): Response {
        if (request != null)
            return super.reliableRequest(requestToDomainRequest(request))
        return super.reliableRequest(request)
    }

    override fun makeRequest(request: Request?): Response {
        if (request != null) {
            val requestToDomain = requestToDomainRequest(request)
            return super.makeRequest(requestToDomain)
        }
        return super.makeRequest(request)
    }

    private fun requestToDomainRequest(request: Request) = Request(
        request.method,
        changeUrlDomain(request.constructURL().toString())
    )

    private fun changeUrlDomain(url: String): String {
        return Regex("http[s]?://.+\\.com").replace(url, domain)
    }
}

I don't know if it's the best approach to handle it.

Thank you for your help !

thinkingserious commented 3 years ago

Nice!!

Thank you for taking the time to share your solution!