Skip to content

Instantly share code, notes, and snippets.

@dev-drprasad
Created July 13, 2018 17:55
Show Gist options
  • Save dev-drprasad/20741429862f05661cb8b8fcf9b3090f to your computer and use it in GitHub Desktop.
Save dev-drprasad/20741429862f05661cb8b8fcf9b3090f to your computer and use it in GitHub Desktop.
wrapper to make requests in nextjs components
import { Fragment } from 'react';
import querystring from 'querystring';
import PropTypes from 'prop-types';
import getTheme from 'styles/getTheme';
import { sanitizeCookies } from 'utils/utils';
import { fetcher } from 'utils/apiCaller';
import logger from 'utils/logger';
import ErrorPage from './ErrorPage';
import getClient from '../getClient';
import clientIdsToBaseUrls from '../clientIdsToBaseUrls';
const PageWrapper = Comp => (
class extends React.Component { // eslint-disable-line no-undef
static async getInitialProps(args) {
const { req, res } = args;
const childProps = Comp.getInitialProps ? await Comp.getInitialProps(args) : null;
const client = getClient(req);
const theme = getTheme(client.clientId);
let apiEndpoint = req.path.replace('.html', '');
const queryParams = { clientId: client.clientId, ...req.query };
const queryParamsAsString = querystring.stringify(queryParams);
if (queryParamsAsString) {
apiEndpoint += `?${queryParamsAsString}`;
}
const headers = req.headers['user-agent'] ? { ...req.headers } : {};
const options = { credentials: 'include', headers };
const response = await fetcher(apiEndpoint, options);
const { data } = response;
if (response.error) {
// since we got error from backend, pick baseUrl from local
const baseUrl = client.isRealClient ? clientIdsToBaseUrls[client.clientId] || '' : '';
// if buy controller fails in backend, pick affiliateUrl from query params and serve
if (req.path === '/buy') {
let affiliateUrl = null;
if (req.query.urls) {
// urls can be single string or list of strings
if (req.query.urls instanceof Array) {
// remove empty values if any before destructuring
[affiliateUrl = null] = req.query.urls.filter(u => !!u);
} else {
affiliateUrl = req.query.urls || null;
}
}
if (affiliateUrl) {
return {
response: { affiliateUrl },
client: { ...client, baseUrl },
error: false,
statusCode: 200,
theme,
...childProps,
};
}
}
if (req.path === '/widget/contextual' || req.path === '/widget/content-associated-product') {
res.writeHead(302, {
Location: `${baseUrl}${req.path}/default`,
});
res.end();
}
res.statusCode = response.statusCode === 404 ? 404 : 502;
return {
data: {}, error: true, statusCode: response.statusCode, client, theme,
};
}
const cookies = sanitizeCookies(response.headers.getAll('set-cookie'));
cookies.forEach((cookie) => {
res.cookie(cookie.name, cookie.value, cookie.config);
});
let baseUrl = '';
if (client.isRealClient) {
baseUrl = data.client && data.client.baseUrl;
if (!baseUrl) {
logger.error('baseUrl is not present in API response. returning 502 bad gateway');
res.statusCode = 502;
return {
data: {}, error: true, statusCode: response.statusCode, client, theme,
};
}
}
if (data.redirectUrl) {
res.writeHead(301, {
Location: baseUrl + data.redirectUrl,
});
res.end();
return {};
}
return {
response: data,
client: { ...client, baseUrl },
error: response.error,
statusCode: response.statusCode,
theme,
...childProps,
};
}
static childContextTypes = {
theme: PropTypes.object,
client: PropTypes.object,
};
static propTypes = {
response: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
client: PropTypes.object.isRequired,
};
getChildContext() {
return {
theme: this.props.theme,
client: this.props.client,
};
}
render() {
const { props } = this;
if (props.error) {
return <ErrorPage statusCode={props.statusCode} />;
}
const {
page: { topPicks: products = [] } = {},
saleProducts = [],
searchTerms = '',
} = this.props.response || {};
const allProducts = [
...saleProducts, ...products,
];
const productIds = [];
allProducts.forEach((product) => {
if (product.id) productIds.push(product.id);
});
return (
<Fragment>
<Comp {...props} />
</Fragment>
);
}
}
);
PageWrapper.propTypes = {
statusCode: PropTypes.number,
isRealClient: PropTypes.bool,
};
export default PageWrapper;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment