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

Fix/api request refactor #30

Merged
merged 10 commits into from
Feb 1, 2018
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!groovy
@Library('jenkins-pipeline-shared@feature/new-cf') _
@Library('jenkins-pipeline-shared@master') _

/*
* bi-ui Jenkins Pipeline
Expand Down
17 changes: 12 additions & 5 deletions src/actions/ApiActions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { SET_RESULTS, SET_FORMATTED_QUERY, SET_SEARCH_ERROR_MESSAGE, SENDING_SEARCH_REQUEST, SET_QUERY, SET_HEADERS } from '../constants/ApiConstants';
import apiSearch from '../utils/apiSearch';
import accessAPI from '../utils/accessAPI';
import config from '../config/api-urls';

const { REROUTE_URL, API_VERSION } = config;

// The search action creator can be used for Match/Range/UBRN searches
export function search(query, formQuery, jsonKey) {
Expand All @@ -10,18 +13,22 @@ export function search(query, formQuery, jsonKey) {
dispatch(setQuery(SET_QUERY, query, jsonKey));
const formattedQuery = formQuery(query);
dispatch(setFormattedQuery(SET_FORMATTED_QUERY, formattedQuery, jsonKey));
apiSearch.search(formattedQuery, (success, data) => {

accessAPI(REROUTE_URL, 'POST', sessionStorage.accessToken, JSON.stringify({
method: 'GET',
endpoint: `${API_VERSION}/${formattedQuery}`,
}), (success, data) => {
dispatch(sendingRequest(SENDING_SEARCH_REQUEST, false, jsonKey));
if (success) {
// This is a workaround for the API returning 200 {} for no results, should be 404
if (Object.keys(data.results).length === 0 && data.results.constructor === Object) {
if (Object.keys(data.json).length === 0 && data.json.constructor === Object) {
dispatch(setErrorMessage(SET_SEARCH_ERROR_MESSAGE, '404: No results found.', jsonKey));
} else {
if (jsonKey === 'ubrn') {
// Wrap the results in an array as we only get {} from the API
dispatch(setResults(SET_RESULTS, [data.results], jsonKey));
dispatch(setResults(SET_RESULTS, [data.json], jsonKey));
} else {
dispatch(setResults(SET_RESULTS, data.results, jsonKey));
dispatch(setResults(SET_RESULTS, data.json, jsonKey));
}
dispatch(setHeaders(SET_HEADERS, data.response, jsonKey));
}
Expand Down
24 changes: 16 additions & 8 deletions src/actions/InfoActions.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { SET_UI_INFO, SET_API_INFO, SENDING_UI_REQUEST, SENDING_API_REQUEST, SET_UI_ERROR_MESSAGE, SET_API_ERROR_MESSAGE } from '../constants/InfoConstants';
import apiInfo from '../utils/apiInfo';
import accessAPI from '../utils/accessAPI';
import config from '../config/api-urls';

const { AUTH_URL, REROUTE_URL } = config;

/**
* Get info (version/last updated) from the Node server
*/
export function getUiInfo() {
return (dispatch) => {
dispatch(sendingRequest(SENDING_UI_REQUEST, true));
apiInfo.getUiInfo((success, data) => {

accessAPI(`${AUTH_URL}/api/info`, 'GET', sessionStorage.accessToken, {}, (success, data) => {
dispatch(sendingRequest(SENDING_UI_REQUEST, false));
if (success) {
dispatch(setInfo(SET_UI_INFO, {
version: data.version,
lastUpdate: data.lastUpdate,
version: data.json.version,
lastUpdate: data.json.lastUpdate,
}));
} else {
dispatch(setErrorMessage(SET_UI_ERROR_MESSAGE, data.message));
Expand All @@ -27,13 +31,17 @@ export function getUiInfo() {
export function getApiInfo() {
return (dispatch) => {
dispatch(sendingRequest(SENDING_API_REQUEST, true));
apiInfo.getApiInfo((success, data) => {

accessAPI(REROUTE_URL, 'POST', sessionStorage.accessToken, JSON.stringify({
method: 'GET',
endpoint: 'version',
}), (success, data) => {
dispatch(sendingRequest(SENDING_API_REQUEST, false));
if (success) {
dispatch(setInfo(SET_API_INFO, {
version: data.version,
lastApiUpdate: data.lastApiUpdate,
lastDataUpdate: data.lastDataUpdate,
version: data.json.version,
lastApiUpdate: data.json.builtAtString,
lastDataUpdate: data.json.lastDataUpdate,
}));
} else {
dispatch(setErrorMessage(SET_API_ERROR_MESSAGE, data.message));
Expand Down
47 changes: 20 additions & 27 deletions src/actions/LoginActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { browserHistory } from 'react-router';
import base64 from 'base-64';
import { SET_AUTH, SET_CONFETTI, USER_LOGOUT, SENDING_REQUEST, SET_ERROR_MESSAGE, SET_USER_DETAILS } from '../constants/LoginConstants';
import * as errorMessages from '../constants/MessageConstants';
import auth from '../utils/auth';
import { getUiInfo, getApiInfo } from '../actions/InfoActions';
import accessAPI from '../utils/accessAPI';
import config from '../config/api-urls';

const { AUTH_URL } = config;

/**
* Logs an user in
Expand All @@ -23,38 +26,28 @@ export function login(username, password) {
}

const basicAuth = base64.encode(`${username}:${password}`);
auth.login(username, basicAuth, (success, data) => {

accessAPI(`${AUTH_URL}/auth/login`, 'POST', `Basic ${basicAuth}`, JSON.stringify({
username,
}), (success, data) => {
// When the request is finished, hide the loading indicator
dispatch(sendingRequest(false));
dispatch(setAuthState(success));
if (success) {
dispatch(setConfetti(data.showConfetti));
dispatch(setConfetti(data.json.showConfetti));
// If the login worked, forward the user to the dashboard and clear the form
dispatch(setUserState({
username,
role: data.role,
accessToken: data.accessToken,
role: data.json.role,
accessToken: data.json.accessToken,
}));
sessionStorage.setItem('accessToken', data.accessToken);
sessionStorage.setItem('accessToken', data.json.accessToken);
sessionStorage.setItem('username', username);
dispatch(getUiInfo());
dispatch(getApiInfo());
// We setQuery to {} as a hacky solution to the issue below:
// https://github.com/ONSdigital/bi-ui/issues/3
// dispatch(setQuery(SET_MATCH_QUERY, {}));
// dispatch(setQuery(SET_RANGE_QUERY, {}));
forwardTo('/Home');
} else {
switch (data.type) {
case 'user-doesnt-exist':
dispatch(setErrorMessage(errorMessages.USER_NOT_FOUND));
return;
case 'password-wrong':
dispatch(setErrorMessage(errorMessages.WRONG_PASSWORD));
return;
default:
dispatch(setErrorMessage(errorMessages.GENERAL_ERROR));
}
dispatch(setErrorMessage(errorMessages.GENERAL_ERROR));
}
});
};
Expand All @@ -63,9 +56,9 @@ export function login(username, password) {
/**
* Check the users token
*/
export function checkAuth(username, token) {
export function checkAuth() {
return (dispatch) => {
auth.checkToken(token, (success, data) => {
accessAPI(`${AUTH_URL}/auth/checkToken`, 'POST', sessionStorage.accessToken, {}, (success, data) => {
dispatch(setAuthState(success));
if (!success) {
sessionStorage.clear();
Expand All @@ -77,11 +70,11 @@ export function checkAuth(username, token) {
dispatch(getUiInfo());
dispatch(getApiInfo());
dispatch(setUserState({
username: data.username,
accessToken: data.newAccessToken,
role: data.role,
username: data.json.username,
accessToken: data.json.accessToken,
role: data.json.role,
}));
sessionStorage.setItem('accessToken', data.newAccessToken);
sessionStorage.setItem('accessToken', data.json.accessToken);
}
});
};
Expand All @@ -93,7 +86,7 @@ export function checkAuth(username, token) {
export function logout() {
return (dispatch) => {
dispatch(sendingRequest(true));
auth.logout(sessionStorage.accessToken, (success) => {
accessAPI(`${AUTH_URL}/auth/logout`, 'POST', sessionStorage.accessToken, {}, (success, data) => {
dispatch(sendingRequest(false));
if (success) {
dispatch(setAuthState(false));
Expand Down
32 changes: 32 additions & 0 deletions src/utils/accessAPI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
*
* @const accessAPI - This encapsulates common fetch parameters
*
* @param {String} url - URL to fetch from
* @param {String} method - The HTTP method
* @param {String} auth - Either basic authentication or the accessToken
* @param {String} body - The request body (as a JSON string)
* @param {Function} callback - The method to call with the fetch results
*
* @return {Function}
*
*/
const accessAPI = (url, method, auth, body, callback) => {
return fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: auth,
},
body,
}).then((response) => {
switch (response.status) {
case 200: return response.json().then((json) => callback(true, { json }));
case 401: return callback(false, { message: 'Authentication problem. Please ensure you are logged in.' });
case 500: return callback(false, { message: 'Server error. Please contact your system administrator.' });
default: return callback(false, { message: `${response.status} error.` });
}
}).catch((err) => callback(false, { message: `Server error: request timed out. ${err}` }));
};

export default accessAPI;
65 changes: 0 additions & 65 deletions src/utils/apiInfo.js

This file was deleted.

40 changes: 0 additions & 40 deletions src/utils/apiSearch.js

This file was deleted.

Loading