Skip to content

Commit

Permalink
feat: remove axios from dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavoerivero committed Oct 12, 2024
1 parent cc19793 commit b3e02b6
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 33 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"@vercel/ncc": "^0.36.1",
"axios": "^1.5.1",
"babel-jest": "^29.7.0",
"cors": "^2.8.5",
"debug": "^4.3.4",
Expand Down
130 changes: 130 additions & 0 deletions src/services/client/http.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import http from 'http';
import https from 'https';

import { RequestOptions, HttpResponse } from './interfaces';
import { BASE_URL } from '..';

export class HttpClient {
private readonly baseUrl?: string;

constructor(baseUrl?: string) {
this.baseUrl = baseUrl;
}

private buildUrl(path: string, queryParameters?: Record<string, string>): string {
let url = this.baseUrl ?? '';

url += path;
if (queryParameters) {
const queryParams = new URLSearchParams(Object.entries(queryParameters));
url += `?${queryParams.toString()}`;
}

return url;
}

private buildRequestOptions<T>(method: RequestOptions<T>['method'], options: RequestOptions<T>): RequestOptions<T> {
const requestOptions: RequestOptions<T> = {
method,
headers: options.headers || {},
};

if (options.body) {
requestOptions.headers!['Content-Type'] = 'application/json';
}

return requestOptions;
}

private async sendRequest<T>(url: string, options: RequestOptions<T>): Promise<HttpResponse<T>> {
const protocol = url.startsWith('http:') ? http : https;

return new Promise((resolve, reject) => {
const request = protocol.request(url, options, (res) => {
let data = '';

res.on('data', (chunk) => {
data += chunk;
});

res.on('end', () => {
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
const response: HttpResponse<T> = {
data: JSON.parse(data),
status: res.statusCode,
statusMessage: res.statusMessage,
headers: res.headers,
};
resolve(response);
} else {
reject(new Error(''));
}
});

res.on('error', (error) => {
reject(new Error(`Request error: ${error}`));
});
});

request.end();
});
}

private async send<T>(
method: RequestOptions<T>['method'],
path: string,
options: RequestOptions<T>,
body?: T,
): Promise<HttpResponse<T>> {
const url = this.buildUrl(path, options.queryParameters);

if (body) {
options.body = body;
}

const requestOptions = this.buildRequestOptions(method, options);

try {
const response = await this.sendRequest<T>(url, requestOptions);
return response;
} catch (error) {
throw new Error(`Request option error: ${error}`);
}
}

public async post<T>(
path: string,
body: T,
options: RequestOptions<T> = { method: 'POST' },
): Promise<HttpResponse<T>> {
return this.send<T>('POST', path, options, body);
}

public async get<T>(path: string, options: RequestOptions<T> = { method: 'GET' }): Promise<HttpResponse<T>> {
return this.send<T>('GET', path, options);
}

public async put<T>(path: string, body: T, options: RequestOptions<T> = { method: 'PUT' }): Promise<HttpResponse<T>> {
return this.send<T>('PUT', path, options, body);
}

public async patch<T>(
path: string,
body: T,
options: RequestOptions<T> = { method: 'PATCH' },
): Promise<HttpResponse<T>> {
return this.send<T>('PATCH', path, options, body);
}

public async delete<T>(
path: string,
body: T,
options: RequestOptions<T> = { method: 'DELETE' },
): Promise<HttpResponse<T>> {
return this.send<T>('DELETE', path, options, body);
}
}

const client = new HttpClient(BASE_URL);

export default client;
15 changes: 15 additions & 0 deletions src/services/client/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import client, { IncomingHttpHeaders } from 'http';

export interface RequestOptions<T> extends client.RequestOptions {
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
headers?: Record<string, string>;
queryParameters?: Record<string, string>;
body?: T;
}

export interface HttpResponse<T> {
data: T;
status?: number;
statusMessage?: string;
headers: Record<string, string> | IncomingHttpHeaders;
}
8 changes: 4 additions & 4 deletions src/services/dollar.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//import * as cheerio from "cheerio"
import { TBsDollarCalculated, TDollar, TDollarAverage, TDollarCalculated, TDollarEntity } from '../types/TDollar';
import { formatDate } from '../utils/formatDate';
import http from './http';
import { TResponse } from '../types';
import { AxiosResponse } from 'axios';
import { HttpResponse } from './client/interfaces';

import api from './client/http';

const ABS = 5;

Expand All @@ -20,7 +21,7 @@ const getTendency = (tendency: number) => {
};

const discard = (pivot: number, minus: number = 0, abs: number = 0) => Math.abs(pivot - minus) - abs > abs;
const getEntity = (data: AxiosResponse<TResponse[], any>, name: string) =>
const getEntity = (data: HttpResponse<TResponse[]>, name: string) =>
data.data.find((item) => item.name.toLowerCase().includes(name));

/**
Expand All @@ -35,7 +36,6 @@ export const getDollarPrices = async (): Promise<TDollar[] | null> => {
// Fetch data from the specified URL

const EXT = '/coins';
const api = http();

const response = await api.get<TResponse[]>(EXT);

Expand Down
17 changes: 14 additions & 3 deletions src/services/euro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const getEuroPrices = async (): Promise<TEuro[] | null> => {

const priceResult: TEuro[] = [];

formatHTML.each((_: number, div: any) => {
formatHTML.each((_: number, div) => {
const title = cheerioData(div).find('h6.nombre').text();

const cheerioDate = cheerioData(div).find('p.fecha').text();
Expand All @@ -59,15 +59,26 @@ export const getEuroPrices = async (): Promise<TEuro[] | null> => {

const [tendency, percentage] = cheerioData(div).find('p.cambio-por').text().replace(',', '.').split(' ');

let tendencyName = 'Unchanged';
let tendencyColor = 'gray';

if (tendency === '▲') {
tendencyName = 'Uptrend';
tendencyColor = 'green';
} else if (tendency === '▼') {
tendencyName = 'Downtrend';
tendencyColor = 'red';
}

const euroData: TEuro = {
title: title,
euro: euro,
updatedDate,
image: BASE_URL + image,
difference: Number(difference ?? 0),
differencePercentage: percentage,
tendency: tendency === '▲' ? 'Uptrend' : tendency === '▼' ? 'Downtrend' : 'Unchanged',
tendencyColor: tendency === '▲' ? 'green' : tendency === '▼' ? 'red' : 'gray',
tendency: tendencyName,
tendencyColor: tendencyColor,
};

priceResult.push(euroData);
Expand Down
19 changes: 0 additions & 19 deletions src/services/http.ts

This file was deleted.

13 changes: 10 additions & 3 deletions src/services/swagger.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import swaggerJsonDoc from 'swagger-jsdoc';
import dotenv from 'dotenv';

dotenv.config();

const API_VER = `${process.env.API_VER}`;
const API_URL = `${process.env.API_VER_URL}`;
const EMAIL = `${process.env.EMAIL}`;

const swaggerOptions = {
openapi: '3.0.0',
definition: {
info: {
title: `Venecodollar API Documentation`,
version: '2.1.0',
version: API_VER,
description: `This section represents the Swagger documentation of the API designed with Venecodollar"s NPM package. Here it is possible to test the endpoints provided by this API.\n\nIf you wish to make use of the NPM package in your javascript or typescript project, please [click here](https://www.npmjs.com/package/venecodollar), where you will be redirected to the official Venecodollar NPM package page.`,
contact: {
name: 'the developer',
email: process.env.EMAIL ?? '',
email: EMAIL,
},
license: {
name: 'MIT',
url: `https://github.com/gustavoerivero/venecodollar/blob/main/LICENSE`,
},
schemes: ['http', 'https'],
servers: [{ url: 'https://venecodollar.vercel.app/api/v1' }],
servers: [{ url: `https://venecodollar.vercel.app${API_URL}` }],
},
},
apis: [`${__dirname}/routes/*.ts`, './build/routes/*.js'],
Expand Down
4 changes: 2 additions & 2 deletions src/utils/formatDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const options = { timeZone };
* @returns {string} The formatted hour in HH:mm AM/PM format.
* @throws {Error} If the date value is missing or in an invalid format.
*/
export const getHour = (date: string | Date | null): string => {
export const getHour = (date?: string | Date): string => {
try {
if (!date) {
throw Error('The date value must exist in date or string format.');
Expand Down Expand Up @@ -139,7 +139,7 @@ export const before24hours = (date: string | Date | null): boolean => {
};

export const convertDate = (text: string) => {
const [_, period] = text.split('Actualizó hace');
const [, period] = text.split('Actualizó hace');

let [unit, time] = period.split(' ').slice(-2);

Expand Down
4 changes: 3 additions & 1 deletion src/utils/responses.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Response } from 'express';
import messages from './messages';

export type Code = 'Success' | 'UnexpectedError' | 'Error';

/**
* Function that generates a JSON response with an error message for HTTP 404 status code.
* @param res Response object from Express.
* @param err Error object to be included in the response.
* @param code Optional code parameter to specify the error message. Defaults to "UnexpectedError".
*/
export const makeResponsesError = (res: Response, err: Error, code?: 'Success' | 'UnexpectedError' | 'Error') => {
export const makeResponsesError = (res: Response, err: Error, code?: Code) => {
const msg = {
OK: 0,
Error: err,
Expand Down

1 comment on commit b3e02b6

@vercel
Copy link

@vercel vercel bot commented on b3e02b6 Oct 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.