diff --git a/package-lock.json b/package-lock.json index 8af1962f1..4f7671e3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12371,7 +12371,7 @@ }, "packages/spacecat-shared-rum-api-client": { "name": "@adobe/spacecat-shared-rum-api-client", - "version": "1.1.0", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "@adobe/fetch": "4.1.1", @@ -12389,12 +12389,21 @@ "typescript": "5.3.2" } }, + "packages/spacecat-shared-rum-api-client/node_modules/@adobe/spacecat-shared-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@adobe/spacecat-shared-utils/-/spacecat-shared-utils-1.3.0.tgz", + "integrity": "sha512-w+A5ZUo80tzt0ni5baoq+PUMkRHlUtFhGt9RtGNwLuhCf2yYP2lhfBTCICn8fpx3lmGkfngXRjaIsgZJWiLO/w==" + }, "packages/spacecat-shared-utils": { "name": "@adobe/spacecat-shared-utils", - "version": "1.3.0", + "version": "1.4.0", "license": "Apache-2.0", + "dependencies": { + "@adobe/fetch": "^4.1.1" + }, "devDependencies": { - "chai": "4.3.10" + "chai": "4.3.10", + "sinon": "17.0.1" } } } diff --git a/packages/spacecat-shared-utils/README.md b/packages/spacecat-shared-utils/README.md index 8734f467d..3dfb186a2 100644 --- a/packages/spacecat-shared-utils/README.md +++ b/packages/spacecat-shared-utils/README.md @@ -45,6 +45,13 @@ The library includes the following utility functions: - `hasText(str)`: Checks if the given string is not empty. - `dateAfterDays(number)`: Calculates the date after a specified number of days from the current date. +The library includes the following http utility functions to create `Response` objects: + +- `ok(body)`: Creates a 200 response with a JSON body. +- `badRequest(message)`: Creates a 400 response with a JSON body. +- `notFound(message)`: Creates a 404 response with a JSON body. +- `internalServerError(message)`: Creates a 500 response with a JSON body. + ## Testing This library includes a comprehensive test suite to ensure the reliability of the utility functions. To run the tests, use the following command: diff --git a/packages/spacecat-shared-utils/package.json b/packages/spacecat-shared-utils/package.json index 1742cb3ff..614ae31d7 100644 --- a/packages/spacecat-shared-utils/package.json +++ b/packages/spacecat-shared-utils/package.json @@ -31,5 +31,8 @@ "devDependencies": { "chai": "4.3.10", "sinon": "17.0.1" + }, + "dependencies": { + "@adobe/fetch": "4.1.1" } } diff --git a/packages/spacecat-shared-utils/src/http-utils.js b/packages/spacecat-shared-utils/src/http-utils.js new file mode 100644 index 000000000..5a0dc25aa --- /dev/null +++ b/packages/spacecat-shared-utils/src/http-utils.js @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { Response } from '@adobe/fetch'; + +/** + * Creates a response with a JSON body. Defaults to 200 status. + * @param {object} body - JSON body. + * @param {number} status - Optional status code. + * @param {object} headers - Optional headers. + * @return {Response} Response. + */ +export function createResponse(body, status = 200, headers = {}) { + return new Response( + JSON.stringify(body), + { + headers: { 'content-type': 'application/json; charset=utf-8', ...headers }, + status, + }, + ); +} +export function ok(body) { + return createResponse(body, 200); +} + +export function noContent(body) { + return createResponse(body, 204); +} + +export function badRequest(message) { + return createResponse({ message }, 400); +} + +export function notFound(message) { + return createResponse({ message }, 404); +} + +export function internalServerError(message) { + return createResponse({ message }, 500, { + 'x-error': `internal server error: ${message}`, + }); +} diff --git a/packages/spacecat-shared-utils/src/index.d.ts b/packages/spacecat-shared-utils/src/index.d.ts index 5f7a590be..26147e79c 100644 --- a/packages/spacecat-shared-utils/src/index.d.ts +++ b/packages/spacecat-shared-utils/src/index.d.ts @@ -10,6 +10,7 @@ * governing permissions and limitations under the License. */ +/** UTILITY FUNCTIONS */ export function arrayEquals(a: T[], b: T[]): boolean; export function hasText(str: string): boolean; @@ -35,3 +36,33 @@ export function toBoolean(value: unknown): boolean; export function isValidUrl(urlString: string): boolean; export function dateAfterDays(days: string): Date; + +/** HTTP UTILS */ + +/** + * Creates a 200 response with a JSON body. + * @param {object} body - JSON body. + * @return {Response} Response. + */ +export function ok(body: object): Response; + +/** + * Creates a 400 response with a JSON body. + * @param {string} message - Error message. + * @return {Response} Response. + */ +export function badRequest(message: string): Response; + +/** + * Creates a 404 response with a JSON body. + * @param {string} message - Error message. + * @return {Response} Response. + */ +export function notFound(message: string): Response; + +/** + * Creates a 500 response with a JSON body. + * @param {string} message - Error message. + * @return {Response} Response. + */ +export function internalServerError(message: string): Response; diff --git a/packages/spacecat-shared-utils/src/index.js b/packages/spacecat-shared-utils/src/index.js index 1378686b3..a7c8036a2 100644 --- a/packages/spacecat-shared-utils/src/index.js +++ b/packages/spacecat-shared-utils/src/index.js @@ -27,4 +27,12 @@ export { dateAfterDays, } from './functions.js'; +export { + ok, + noContent, + badRequest, + notFound, + internalServerError, +} from './http-utils.js'; + export { resolveSecretsName } from './helpers.js'; diff --git a/packages/spacecat-shared-utils/test/http-utils.test.js b/packages/spacecat-shared-utils/test/http-utils.test.js new file mode 100644 index 000000000..3450bb986 --- /dev/null +++ b/packages/spacecat-shared-utils/test/http-utils.test.js @@ -0,0 +1,52 @@ +/* + * Copyright 2023 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +/* eslint-env mocha */ +import { expect } from 'chai'; +import { + ok, badRequest, notFound, internalServerError, +} from '../src/http-utils.js'; + +describe('http-utils', () => { + it('ok should return a 200 response with JSON body', async () => { + const body = { key: 'value' }; + const response = ok(body); + expect(response.status).to.equal(200); + expect(response.headers.get('content-type')).to.equal('application/json; charset=utf-8'); + const respJson = await response.json(); + expect(respJson).to.eql(body); + }); + + it('badRequest should return a 400 response with JSON body', async () => { + const response = badRequest('Bad Request'); + expect(response.status).to.equal(400); + expect(response.headers.get('content-type')).to.equal('application/json; charset=utf-8'); + const respJson = await response.json(); + expect(respJson).to.eql({ message: 'Bad Request' }); + }); + + it('notFound return a 404 response with JSON body', async () => { + const response = notFound('Not Found'); + expect(response.status).to.equal(404); + expect(response.headers.get('content-type')).to.equal('application/json; charset=utf-8'); + const respJson = await response.json(); + expect(respJson).to.eql({ message: 'Not Found' }); + }); + + it('internalServerError should return a 500 response with JSON body', async () => { + const response = internalServerError('uh oh'); + expect(response.status).to.equal(500); + expect(response.headers.get('content-type')).to.equal('application/json; charset=utf-8'); + expect(response.headers.get('x-error')).to.equal('internal server error: uh oh'); + const respJson = await response.json(); + expect(respJson).to.eql({ message: 'uh oh' }); + }); +}); diff --git a/packages/spacecat-shared-utils/test/index.test.js b/packages/spacecat-shared-utils/test/index.test.js index e6333939d..3f7bc8da2 100644 --- a/packages/spacecat-shared-utils/test/index.test.js +++ b/packages/spacecat-shared-utils/test/index.test.js @@ -32,6 +32,11 @@ describe('Index Exports', () => { 'isValidUrl', 'resolveSecretsName', 'dateAfterDays', + 'ok', + 'noContent', + 'badRequest', + 'notFound', + 'internalServerError', ]; it('exports all expected functions', () => {