Skip to content

Commit

Permalink
Support custom headers (#275)
Browse files Browse the repository at this point in the history
  • Loading branch information
ugurakkurt authored Jun 11, 2020
1 parent 0c666fd commit 8ba2f95
Show file tree
Hide file tree
Showing 16 changed files with 96 additions and 4 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ type Props = {
pingOnlyIfOffline?: boolean = false,
pingInBackground?: boolean = false,
httpMethod?: HTTPMethod = 'HEAD',
customHeaders?: HTTPHeaders = {},
}
```

Expand All @@ -140,6 +141,8 @@ type Props = {

`httpMethod`: http method used to ping the server. Supports HEAD or OPTIONS. Defaults to `HEAD`.

`customHeaders`: optional custom headers to add for ping request.

##### Usage
```js
// index.js
Expand Down
2 changes: 2 additions & 0 deletions src/components/NetworkConnectivity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class NetworkConnectivity extends React.PureComponent<
pingTimeout,
pingServerUrl,
httpMethod,
customHeaders,
} = this.props;
if (pingInBackground === false && AppState.currentState !== 'active') {
return; // <-- Return early as we don't care about connectivity if app is not in foreground.
Expand All @@ -123,6 +124,7 @@ class NetworkConnectivity extends React.PureComponent<
url: pingServerUrl,
timeout: pingTimeout,
method: httpMethod,
customHeaders,
}),
NetInfo.fetch(),
]);
Expand Down
17 changes: 17 additions & 0 deletions src/redux/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ export function createIntervalChannel(interval: number, channelFn: Function) {
* @param pingServerUrl
* @param shouldPing
* @param httpMethod
* @param customHeaders
*/

export function* netInfoChangeSaga({
pingTimeout,
pingServerUrl,
shouldPing,
httpMethod,
customHeaders,
}: NetInfoChangeArgs) {
if (Platform.OS === 'android') {
const networkState: NetInfoState = yield call([NetInfo, NetInfo.fetch]);
Expand All @@ -79,6 +81,7 @@ export function* netInfoChangeSaga({
pingTimeout,
pingServerUrl,
httpMethod,
customHeaders,
});
}
const chan = yield call(
Expand All @@ -94,6 +97,7 @@ export function* netInfoChangeSaga({
pingTimeout,
pingServerUrl,
httpMethod,
customHeaders,
});
}
} finally {
Expand All @@ -110,6 +114,7 @@ export function* netInfoChangeSaga({
* @param pingTimeout
* @param pingServerUrl
* @param httpMethod
* @param customHeaders
* @returns {IterableIterator<ForkEffect | *>}
*/

Expand All @@ -119,13 +124,15 @@ export function* connectionHandler({
pingTimeout,
pingServerUrl,
httpMethod,
customHeaders,
}: NetInfoChangeArgs & { isConnected: boolean }) {
if (shouldPing && isConnected) {
yield fork(checkInternetAccessSaga, {
pingTimeout,
pingServerUrl,
httpMethod,
pingInBackground: false,
customHeaders,
});
} else {
yield fork(handleConnectivityChange, isConnected);
Expand All @@ -140,6 +147,7 @@ export function* connectionHandler({
* @param pingOnlyIfOffline
* @param pingInBackground
* @param httpMethod
* @param customHeaders
* @returns {IterableIterator<*>}
*/
export function* connectionIntervalSaga({
Expand All @@ -149,6 +157,7 @@ export function* connectionIntervalSaga({
pingOnlyIfOffline,
pingInBackground,
httpMethod,
customHeaders,
}: Omit<ConnectivityArgs, 'shouldPing'>) {
const chan = yield call(
createIntervalChannel,
Expand All @@ -165,6 +174,7 @@ export function* connectionIntervalSaga({
pingServerUrl,
httpMethod,
pingInBackground,
customHeaders,
});
}
}
Expand All @@ -181,13 +191,15 @@ export function* connectionIntervalSaga({
* @param pingTimeout
* @param httpMethod
* @param pingInBackground
* @param customHeaders
*/

export function* checkInternetAccessSaga({
pingServerUrl,
pingTimeout,
httpMethod,
pingInBackground,
customHeaders,
}: CheckInternetArgs) {
if (pingInBackground === false && AppState.currentState !== 'active') {
return; // <-- Return early as we don't care about connectivity if app is not in foreground.
Expand All @@ -196,6 +208,7 @@ export function* checkInternetAccessSaga({
url: pingServerUrl,
timeout: pingTimeout,
method: httpMethod,
customHeaders,
});
yield call(handleConnectivityChange, hasInternetAccess);
}
Expand Down Expand Up @@ -224,6 +237,7 @@ export function* handleConnectivityChange(hasInternetAccess: boolean) {
* @param pingOnlyIfOffline
* @param pingInBackground
* @param httpMethod
* @param customHeaders
*/
export default function* networkSaga(args?: ConnectivityArgs) {
const {
Expand All @@ -234,13 +248,15 @@ export default function* networkSaga(args?: ConnectivityArgs) {
pingOnlyIfOffline = false,
pingInBackground = false,
httpMethod = DEFAULT_HTTP_METHOD,
customHeaders,
} = args || DEFAULT_ARGS;

yield fork(netInfoChangeSaga, {
pingTimeout,
pingServerUrl,
shouldPing,
httpMethod,
customHeaders,
});
if (pingInterval > 0) {
yield fork(connectionIntervalSaga, {
Expand All @@ -250,6 +266,7 @@ export default function* networkSaga(args?: ConnectivityArgs) {
pingOnlyIfOffline,
pingInBackground,
httpMethod,
customHeaders,
});
}
}
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export type ConnectivityArgs = {
pingOnlyIfOffline: boolean;
pingInBackground: boolean;
httpMethod: HTTPMethod;
customHeaders?: HTTPHeaders;
};

export type SemaphoreColor = 'RED' | 'GREEN';

export type HTTPHeaders = {
[key: string]: string;
};
7 changes: 6 additions & 1 deletion src/utils/checkInternetAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import {
DEFAULT_HTTP_METHOD,
DEFAULT_PING_SERVER_URL,
DEFAULT_TIMEOUT,
DEFAULT_CUSTOM_HEADERS,
} from './constants';
import { HTTPMethod, AddUndefined } from '../types';
import { HTTPMethod, AddUndefined, HTTPHeaders } from '../types';

type Arguments = {
url: string;
timeout: number;
method?: HTTPMethod;
customHeaders: HTTPHeaders;
};

const DEFAULT_ARGUMENTS: Arguments = {
timeout: DEFAULT_TIMEOUT,
url: DEFAULT_PING_SERVER_URL,
method: DEFAULT_HTTP_METHOD,
customHeaders: DEFAULT_CUSTOM_HEADERS,
};
export default function checkInternetAccess(
args?: AddUndefined<Arguments>,
Expand All @@ -24,6 +27,7 @@ export default function checkInternetAccess(
timeout = DEFAULT_TIMEOUT,
url = DEFAULT_PING_SERVER_URL,
method = DEFAULT_HTTP_METHOD,
customHeaders = DEFAULT_CUSTOM_HEADERS,
} = args || DEFAULT_ARGUMENTS;

return new Promise(async (resolve: (value: boolean) => void) => {
Expand All @@ -32,6 +36,7 @@ export default function checkInternetAccess(
method,
url,
timeout,
customHeaders,
});
resolve(true);
} catch (e) {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/checkInternetConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {
DEFAULT_PING_SERVER_URL,
DEFAULT_TIMEOUT,
DEFAULT_HTTP_METHOD,
DEFAULT_CUSTOM_HEADERS,
} from './constants';
import { HTTPMethod } from '../types';
import { HTTPMethod, HTTPHeaders } from '../types';

/**
* Utility that allows to query for internet connectivity on demand
Expand All @@ -20,13 +21,15 @@ export default async function checkInternetConnection(
timeout: number = DEFAULT_TIMEOUT,
shouldPing = true,
method: HTTPMethod = DEFAULT_HTTP_METHOD,
customHeaders: HTTPHeaders = DEFAULT_CUSTOM_HEADERS,
): Promise<boolean> {
return NetInfo.fetch().then(async connectionState => {
if (shouldPing) {
const hasInternetAccess = await checkInternetAccess({
timeout,
url,
method,
customHeaders,
});
return hasInternetAccess;
}
Expand Down
2 changes: 2 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const CACHE_HEADER_VALUE = 'no-cache, no-store, must-revalidate';
export const DEFAULT_TIMEOUT = 10000;
export const DEFAULT_PING_SERVER_URL = 'https://www.google.com/';
export const DEFAULT_HTTP_METHOD = 'HEAD';
export const DEFAULT_CUSTOM_HEADERS = {};
export const SEMAPHORE_COLOR: Record<SemaphoreColor, SemaphoreColor> = {
RED: 'RED',
GREEN: 'GREEN',
Expand All @@ -17,4 +18,5 @@ export const DEFAULT_ARGS: ConnectivityArgs = {
pingOnlyIfOffline: false,
pingInBackground: false,
httpMethod: DEFAULT_HTTP_METHOD,
customHeaders: DEFAULT_CUSTOM_HEADERS,
};
11 changes: 9 additions & 2 deletions src/utils/makeHttpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import {
DEFAULT_PING_SERVER_URL,
DEFAULT_TIMEOUT,
CACHE_HEADER_VALUE,
DEFAULT_CUSTOM_HEADERS,
} from './constants';
import { HTTPHeaders } from '../types';

type Options = {
method?: 'HEAD' | 'OPTIONS';
Expand All @@ -16,6 +18,7 @@ type Options = {
| 'onload/5xx'
| 'onerror'
| 'ontimeout';
customHeaders?: HTTPHeaders;
};

type ResolvedValue = {
Expand All @@ -34,6 +37,7 @@ export const headers = {
* @param url
* @param timeout -> Timeout for rejecting the promise and aborting the API request
* @param testMethod: for testing purposes
* @param customHeaders: headers received from user configuration.
* @returns {Promise}
*/

Expand All @@ -42,12 +46,14 @@ const DEFAULT_OPTIONS: Options = {
method: DEFAULT_HTTP_METHOD,
url: DEFAULT_PING_SERVER_URL,
timeout: DEFAULT_TIMEOUT,
customHeaders: DEFAULT_CUSTOM_HEADERS,
};
export default function makeHttpRequest(args?: Options) {
const {
method = DEFAULT_HTTP_METHOD,
url = DEFAULT_PING_SERVER_URL,
timeout = DEFAULT_TIMEOUT,
customHeaders = DEFAULT_CUSTOM_HEADERS,
testMethod,
} = args || DEFAULT_OPTIONS;
return new Promise((resolve: PromiseHandler, reject: PromiseHandler) => {
Expand Down Expand Up @@ -78,9 +84,10 @@ export default function makeHttpRequest(args?: Options) {
});
};

Object.keys(headers).forEach(key => {
const combinedHeaders = { ...headers, ...customHeaders };
Object.keys(combinedHeaders).forEach(key => {
const k = key as keyof typeof headers;
xhr.setRequestHeader(k, headers[k]);
xhr.setRequestHeader(k, combinedHeaders[k]);
});
xhr.send(null);
});
Expand Down
3 changes: 3 additions & 0 deletions test/NetworkConnectivity.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import NetworkConnectivity, {
import { clear, setup } from '../src/utils/checkConnectivityInterval';
import checkInternetAccess from '../src/utils/checkInternetAccess';
import entries from '../src/utils/objectEntries';
import { DEFAULT_CUSTOM_HEADERS } from '../src/utils/constants';

type OptionalProps = Omit<RequiredProps, 'children'>;
type GetElementParams<P = any> = {
Expand Down Expand Up @@ -270,6 +271,7 @@ describe('NetworkConnectivity', () => {
pingServerUrl: 'dummy.com',
httpMethod: 'OPTIONS' as 'OPTIONS',
children: ChildrenComponent,
customHeaders: DEFAULT_CUSTOM_HEADERS,
};
AppState.currentState = 'active';
const wrapper = shallow<NetworkConnectivity>(
Expand All @@ -283,6 +285,7 @@ describe('NetworkConnectivity', () => {
url: props.pingServerUrl,
timeout: props.pingTimeout,
method: props.httpMethod,
customHeaders: props.customHeaders,
});
expect(mockHandleConnectivityChange).toHaveBeenCalledWith({
isConnected: true,
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/NetworkConnectivity.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`NetworkConnectivity defaultProps 1`] = `
Object {
"customHeaders": Object {},
"httpMethod": "HEAD",
"onConnectivityChange": [Function],
"pingInBackground": false,
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/NetworkProvider.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`NetworkProvider has the correct structure and default props 1`] = `
<NetworkConnectivity
customHeaders={Object {}}
httpMethod="HEAD"
onConnectivityChange={[Function]}
pingInBackground={true}
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/ReduxNetworkProvider.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`ReduxNetworkProvider render has the correct structure 1`] = `
<NetworkConnectivity
customHeaders={Object {}}
dispatch={[MockFunction]}
httpMethod="HEAD"
isConnected={false}
Expand Down
Loading

0 comments on commit 8ba2f95

Please sign in to comment.