Skip to content

Commit

Permalink
feat: make maintenance-related 503s more intuitive (#5018)
Browse files Browse the repository at this point in the history
This makes maintenance-related 503s more intuitive on our UI by
mentioning that maintenance banner is currently enabled.


![image](https://github.com/Unleash/unleash/assets/14320932/43142c58-6b87-4b2d-9239-50f2bb1409e6)
  • Loading branch information
nunogois authored Oct 16, 2023
1 parent c41f23a commit 6c21ed5
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 7 deletions.
1 change: 1 addition & 0 deletions frontend/src/constants/statusCodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const CREATED = 201;
export const NOT_FOUND = 404;
export const FORBIDDEN = 403;
export const UNAUTHORIZED = 401;
export const UNAVAILABLE = 503;
20 changes: 20 additions & 0 deletions frontend/src/hooks/api/actions/useApi/useApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
NOT_FOUND,
OK,
UNAUTHORIZED,
UNAVAILABLE,
} from 'constants/statusCodes';
import {
AuthenticationError,
BadRequestError,
ForbiddenError,
headers,
NotFoundError,
UnavailableError,
} from 'utils/apiUtils';
import { formatApiPath } from 'utils/formatPath';
import { ACCESS_DENIED_TEXT } from 'utils/formatAccessText';
Expand All @@ -27,6 +29,7 @@ interface IUseAPI {
handleNotFound?: ApiErrorHandler;
handleUnauthorized?: ApiErrorHandler;
handleForbidden?: ApiErrorHandler;
handleUnavailable?: ApiErrorHandler;
propagateErrors?: boolean;
}

Expand All @@ -35,6 +38,7 @@ const useAPI = ({
handleNotFound,
handleForbidden,
handleUnauthorized,
handleUnavailable,
propagateErrors = false,
}: IUseAPI) => {
const [errors, setErrors] = useState<Record<string, string>>({});
Expand Down Expand Up @@ -104,6 +108,22 @@ const useAPI = ({
}
}

if (res.status === UNAVAILABLE) {
if (handleUnavailable) {
return handleUnavailable(setErrors, res, requestId);
} else {
setErrors((prev) => ({
...prev,
unavailable: 'This operation is unavailable',
}));
}

if (propagateErrors) {
const response = await res.json();
throw new UnavailableError(res.status, response);
}
}

if (res.status > 399) {
const response = await res.json();
if (response?.details?.length > 0 && propagateErrors) {
Expand Down
25 changes: 19 additions & 6 deletions frontend/src/utils/apiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import {
FORBIDDEN,
NOT_FOUND,
UNAUTHORIZED,
UNAVAILABLE,
} from 'constants/statusCodes';

export interface IErrorBody {
message?: string;
details?: { message: string }[];
}

const getErrorMessage = (body: IErrorBody) =>
body.details?.[0]?.message || body.message;

export class AuthenticationError extends Error {
statusCode: number;

Expand All @@ -24,23 +29,31 @@ export class ForbiddenError extends Error {
body: IErrorBody;

constructor(statusCode: number = FORBIDDEN, body: IErrorBody = {}) {
super(
body.details?.length
? body.details[0].message
: 'You cannot perform this action',
);
super(getErrorMessage(body) || 'You cannot perform this action');
this.name = 'ForbiddenError';
this.statusCode = statusCode;
this.body = body;
}
}

export class UnavailableError extends Error {
statusCode: number;
body: IErrorBody;

constructor(statusCode: number = UNAVAILABLE, body: IErrorBody = {}) {
super(getErrorMessage(body) || 'This operation is unavailable');
this.name = 'UnavailableError';
this.statusCode = statusCode;
this.body = body;
}
}

export class BadRequestError extends Error {
statusCode: number;
body: IErrorBody;

constructor(statusCode: number = BAD_REQUEST, body: IErrorBody = {}) {
super(body.details?.length ? body.details[0].message : 'Bad request');
super(getErrorMessage(body) || 'Bad request');
this.name = 'BadRequestError';
this.statusCode = statusCode;
this.body = body;
Expand Down
7 changes: 6 additions & 1 deletion src/lib/middleware/maintenance-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { IUnleashConfig } from '../types';
import MaintenanceService from '../services/maintenance-service';
import { IAuthRequest } from '../routes/unleash-types';

export const MAINTENANCE_MODE_ENABLED =
'Unleash is currently in maintenance mode.';

const maintenanceMiddleware = (
{ getLogger }: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
maintenanceService: MaintenanceService,
Expand All @@ -17,7 +20,9 @@ const maintenanceMiddleware = (
writeMethod &&
(await maintenanceService.isMaintenanceMode())
) {
res.status(503).send({});
res.status(503).send({
message: MAINTENANCE_MODE_ENABLED,
});
} else {
next();
}
Expand Down

0 comments on commit 6c21ed5

Please sign in to comment.