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

Better way to intercept Twilio module #346

Open
dkundel opened this issue Sep 13, 2021 · 0 comments
Open

Better way to intercept Twilio module #346

dkundel opened this issue Sep 13, 2021 · 0 comments

Comments

@dkundel
Copy link
Member

dkundel commented Sep 13, 2021

I was trying to see how this guide would fit together with the Serverless Toolkit and realized while it works there is some hackery around it.

Essentially the only way you can get this to work without modifying your source code for Functions is by using the LocalDevelopmentServer from @twilio/runtime-handler/dev and initializing it with a basePath that contains a node_modules/twilio/index.js file that contains code similar to this:

const actualTwilio = require('../../../../node_modules/twilio/index');
const { MockHttpClient } = require('../../MockHttpClient');

function interceptedTwilio(username, password, options) {
  const client = actualTwilio(username, password, {...options, httpClient: new MockHttpClient()})
  return client;
}

function fakeTwilio(...args) {
  return interceptedTwilio(...args);
}

fakeTwilio.twiml = actualTwilio.twiml;
fakeTwilio.jwt = actualTwilio.jwt;
fakeTwilio.RequestClient = actualTwilio.RequestClient;
fakeTwilio.Twilio = interceptedTwilio;

module.exports = fakeTwilio;

and then have a MockHttpClient class such as this one:

const { RequestClient } = require('../../node_modules/twilio/index');

class MockHttpClient {
  constructor() {
    this.requestClient = new RequestClient();
  }

  async request(opts) {
    opts.uri = opts.uri.replace(
      `https://sync.twilio.com`,
      'http://localhost:4001'
    );
    opts.uri = opts.uri.replace(
      `https://api.twilio.com`,
      'http://localhost:4002'
    );
    const result = await this.requestClient.request(opts);
    if (result.body.meta) {
      result.body.meta.next_page_url = null;
      result.body.meta.previous_page_url = null;
      result.body.meta.key = Object.keys(result.body)[0];
    }

    return result;
  }
}

exports.MockHttpClient = MockHttpClient;

I think while this is certainly a power-user feature we could make it at least a bit more accessible by making it easier to swap out the Twilio client that is being used. I don't think we need to offer a full mocking capability for npm module since that's what you should use jest or similar tests for but it would be nice to make this behavior easier.

There are three options in my opinion.

Option 1: The most flexible and verbose option

Provide a way to pass your own twilio module into the LocalDevelopmentServer. So rather than doing the requireFromProject() calls everywhere, we'd allow to pass the Twilio Node library as an object into LocalDevelopmentServer.

The problem with this one could be around the process forking and how to pass around the library in this case. A workaround could be to provide a path to a file instead.

Option 2: The middle ground

Add support to the LocalDevelopmentServer config object a new property called twilioDefaultOptions that can be used to provide any of the options that you'd pass otherwise to the twilio constructor call. This includes the httpClient property but also other properties such as edge, region, logLevel or userAgentExtensions.

The main benefit of this one is that we could probably re-use this in some places ourselves as part of the Toolkit but I foresee some issues around process forking again when passing a class for exampl ein the case of httpClient. Hence this wouldn't actually solve this problem when process forking is turned on but that might be fine.

Option 3: The least flexible way

In this situation we'd allow LocalDevelopmentServer to receive a requestRewriteMap that would look something like this:

	requestRewriteMap: {
		'https://sync.twilio.com': 'http://localhost:4001',
		'https://api.twilio.com': 'http://localhost:4002',
	}

And then if we detect that we inject our own MockHTTPServer similar to the one above.

This is by far the most inflexible one but would work with process forking and would require the least amount of set up from the user.

@makserik makserik added this to the Improvements/Nice to haves milestone Mar 25, 2024
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