Skip to content

Commit

Permalink
Merge pull request #402 from mailgun/add-proxy-configuration
Browse files Browse the repository at this point in the history
feature: Add proxy configuration to the client
  • Loading branch information
olexandr-mazepa committed Jan 31, 2024
2 parents 821045d + 3f19d4a commit c04a97a
Show file tree
Hide file tree
Showing 8 changed files with 24,480 additions and 42 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@ Primary accounts can make API calls on behalf of their subaccounts. [API documen
// then, if you need to reset it back to the primary account:
mg.resetSubaccount();
```

### Proxy configuration
By leveraging client configuration options, users can effortlessly establish proxy connections that align with their network requirements.
Ex:
```js
import * as FormData from 'form-data';
import Mailgun from 'mailgun.js';
const mailgun = new Mailgun(FormData);

const mg = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY || 'key-yourkeyhere',
proxy: {
protocol: 'https' // 'http' ,
host: '127.0.0.1', // use your proxy host here
port: 9000, // use your proxy port here
auth: { // may be omitted if proxy doesn't require authentication
username: 'user_name', // provide username
password: 'user_password' // provide password
}
},
});
```
### Types imports
Starting from version **9.0.0.** Types can be includes as named import:
```TS
Expand Down
1 change: 1 addition & 0 deletions dist/Classes/common/Request.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ declare class Request {
private headers;
private formDataBuilder;
private maxBodyLength;
private proxy;
constructor(options: RequestOptions, formData: InputFormData);
request(method: string, url: string, onCallOptions?: Record<string, unknown | Record<string, unknown>>): Promise<APIResponse>;
private getResponseBody;
Expand Down
2 changes: 2 additions & 0 deletions dist/Types/MailgunClient/MailgunClientOptions.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { AxiosProxyConfig } from 'axios';
export type MailgunClientOptions = {
username: string;
key: string;
url?: string;
public_key?: string;
timeout?: number;
proxy?: AxiosProxyConfig;
};
14,564 changes: 14,561 additions & 3 deletions dist/mailgun.node.js

Large diffs are not rendered by default.

9,807 changes: 9,804 additions & 3 deletions dist/mailgun.web.js

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions lib/Classes/common/Request.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import * as base64 from 'base-64';
import urljoin from 'url-join';
import axios, {
AxiosError, AxiosResponse, AxiosHeaders, RawAxiosRequestHeaders
AxiosError,
AxiosResponse,
AxiosHeaders,
RawAxiosRequestHeaders,
AxiosProxyConfig,
} from 'axios';
import * as NodeFormData from 'form-data';
import APIError from './Error';
Expand All @@ -25,6 +29,7 @@ class Request {
private headers: AxiosHeaders;
private formDataBuilder: FormDataBuilder;
private maxBodyLength: number;
private proxy: AxiosProxyConfig | undefined;

constructor(options: RequestOptions, formData: InputFormData) {
this.username = options.username;
Expand All @@ -34,6 +39,7 @@ class Request {
this.headers = this.makeHeadersFromObject(options.headers);
this.formDataBuilder = new FormDataBuilder(formData);
this.maxBodyLength = 52428800; // 50 MB
this.proxy = options?.proxy;
}

async request(
Expand Down Expand Up @@ -66,7 +72,8 @@ class Request {
url: urlValue,
headers: requestHeaders,
...params,
maxBodyLength: this.maxBodyLength
maxBodyLength: this.maxBodyLength,
proxy: this.proxy,
});
} catch (err: unknown) {
const errorResponse = err as AxiosError;
Expand Down
2 changes: 2 additions & 0 deletions lib/Types/MailgunClient/MailgunClientOptions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { AxiosProxyConfig } from 'axios';
/* eslint-disable camelcase */
export type MailgunClientOptions = {
username: string;
key: string;
url?: string;
public_key?: string;
timeout?: number;
proxy?: AxiosProxyConfig;
}
112 changes: 78 additions & 34 deletions test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import DomainTemplatesClient from '../lib/Classes/Domains/domainsTemplates';
import MultipleValidationClient from '../lib/Classes/Validations/multipleValidation';
import MailListsMembers from '../lib/Classes/MailingLists/mailListMembers';

describe('Client', function () {
describe('Client', () => {
let client: IMailgunClient;

beforeEach(function () {
beforeEach(() => {
client = new Client({
username: 'username',
key: 'key',
Expand All @@ -37,27 +37,11 @@ describe('Client', function () {
}, formData as InputFormData);
});

it('raises error when username is not provided', function () {
expect(
function () {
return new Client({ key: 'key' } as MailgunClientOptions, formData as InputFormData);
}
).to.throw('Parameter "username" is required');
});

it('raises error when key is not provided', function () {
expect(
function () {
return new Client({ username: 'username' } as MailgunClientOptions, formData as InputFormData);
}
).to.throw('Parameter "key" is required');
});

it('exposes raw request client', function () {
it('exposes raw request client', () => {
client.should.have.property('request').to.be.instanceOf(Request);
});

it('sets and resets subaccount header for requests', function () {
it('sets and resets subaccount header for requests', () => {
client.setSubaccount('XYZ');
client.should.have.property('request').to.be.instanceOf(Request);
client.should.have.property('request').to.haveOwnProperty('headers')
Expand All @@ -67,7 +51,7 @@ describe('Client', function () {
.to.not.haveOwnProperty(SubaccountsClient.SUBACCOUNT_HEADER);
});

it('creates domain client', function () {
it('creates domain client', () => {
client.domains.should.be.instanceOf(DomainsClient);
});

Expand All @@ -83,55 +67,115 @@ describe('Client', function () {
client.domains.domainTemplates.should.be.instanceOf(DomainTemplatesClient);
});

it('creates event client', function () {
it('creates event client', () => {
client.events.should.be.instanceOf(EventsClient);
});

it('creates webhook client', function () {
it('creates webhook client', () => {
client.webhooks.should.be.instanceOf(WebhooksClient);
});

it('creates suppressions client', function () {
it('creates suppressions client', () => {
client.suppressions.should.be.instanceOf(SuppressionsClient);
});

it('creates stats client', function () {
it('creates stats client', () => {
client.stats.should.be.instanceOf(StatsClient);
});

it('creates messages client', function () {
it('creates messages client', () => {
client.messages.should.be.instanceOf(MessagesClient);
});

it('creates routes client', function () {
it('creates routes client', () => {
client.routes.should.be.instanceOf(RoutesClient);
});

it('creates ips client', function () {
it('creates ips client', () => {
client.ips.should.be.instanceOf(IpsClient);
});

it('creates ip_pools client', function () {
it('creates ip_pools client', () => {
client.ip_pools.should.be.instanceOf(IpPoolsClient);
});

it('creates lists client', function () {
it('creates lists client', () => {
client.lists.should.be.instanceOf(ListsClient);
});

it('creates mail lists members client', function () {
it('creates mail lists members client', () => {
client.lists.members.should.be.instanceOf(MailListsMembers);
});

it('creates address validate client', function () {
it('creates address validate client', () => {
client.validate.should.be.instanceOf(ValidateClient);
});

it('creates multiple validation client', function () {
it('creates multiple validation client', () => {
client.validate.multipleValidation.should.be.instanceOf(MultipleValidationClient);
});

it('creates subaccounts client', function () {
it('creates subaccounts client', () => {
client.subaccounts.should.be.instanceOf(SubaccountsClient);
});

describe('User configuration', () => {
it('respects proxy settings', () => {
const mgClient = new Client({
username: 'username',
key: 'key',
public_key: 'key',
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'test',
password: 'test-pass'
}
}
} as MailgunClientOptions, formData as InputFormData);
mgClient.should.have.property('request');
mgClient.should.have.property('request').to.have.property('proxy').to.eql({
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'test',
password: 'test-pass'
}
});
});

it('respects timeout and url settings', () => {
const mgClient = new Client({
username: 'username',
key: 'key',
public_key: 'public_key',
timeout: 1000,
url: 'test_url'
} as MailgunClientOptions, formData as InputFormData);
mgClient.should.have.property('request');
mgClient.should.have.property('request').to.have.property('timeout').to.equal(1000);
mgClient.should.have.property('request').to.have.property('url').to.eql('test_url');
});

it('raises error when username is not provided', () => {
expect(
() => new Client(
{ key: 'key' } as MailgunClientOptions,
formData as InputFormData
)
).to.throw('Parameter "username" is required');
});

it('raises error when key is not provided', () => {
expect(
() => new Client(
{ username: 'username' } as MailgunClientOptions,
formData as InputFormData
)
).to.throw('Parameter "key" is required');
});
});
});

0 comments on commit c04a97a

Please sign in to comment.