Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Boas práticas de SOLID em useFetch

Boa tarde, tudo bem?

Sabendo-se dos princípios do SOLID, em relação ao hook customizado useFecth e suas dependências. Seria uma boa prática tornar o useFecth passível de implementar demais métodos REST?, tais como POST, PUT e DELETE ao invés de somente o GET ?

Sendo assim, na interface de contrato deveria ser definido os demais métodos ( post, put e delete )

export interface IHttp {
  get<T>(url: string): Promise<T>;
}

No arquivo Http também deveria ser implementado os demais métodos

import axios from "axios";

import { IHttp } from "./http.interface";

const Http = (): IHttp => {
  return {
    get: async <T>(url: string): Promise<T> => {
      return axios.get(url).then((response) => response.data);
    },
  };
};

export default Http;

E no arquivo useFetch, também deveria ser modificado para adicionar demais métodos para ser escolhidos no contexto desejado, ou seja, podendo fazer POST, GET, PUT e DELETE

import { useEffect, useState } from "react";
import Http from "../../lib/httpClient";
import { IHttp } from "../../lib/httpClient/http.interface";

type FetchResult<T> = {
  data: T | null;
  isLoading: boolean;
  error: string | null;
};

const useFetch = <T>(url: string): FetchResult<T> => {
  const [data, setData] = useState<T | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);

  const http: IHttp = Http();

  useEffect(() => {
    setIsLoading(true);

    http
      .get<T>(url)
      .then((response) => {
        setData(response);
        setIsLoading(false);
      })
      .catch((error) => {
        setError("Erro ao carregar dados!");
        setIsLoading(false);
      });
  }, [url]);

  return { data, isLoading, error };
};

export default useFetch;

Como seria aplicar isso? Ainda seria uma prática que estaria dentro dos requisitos do SOLID, ou seria infringido?

Obrigado.

Felipe D.R

2 respostas
solução!

Expandir o useFetch para suportar outros métodos HTTP pode ser válido, mas pode afetar o princípio da Segregação de Interface (ISP) e o Princípio da Responsabilidade Única (SRP). Seu hook atualmente só lida com GET, o que o torna mais coeso.

Se o objetivo for tornar a API de requisições mais flexível, uma abordagem melhor seria criar um serviço separado que implementa os métodos POST, PUT e DELETE e, se necessário, criar hooks específicos para cada caso, como usePost, usePut e useDelete.

export interface IHttp {
  get<T>(url: string): Promise<T>;
  post<T>(url: string, body: any): Promise<T>;
  put<T>(url: string, body: any): Promise<T>;
  delete<T>(url: string): Promise<T>;
}

E a implementação poderia ser:

const Http = (): IHttp => {
  return {
    get: async <T>(url: string): Promise<T> => axios.get(url).then((res) => res.data),
    post: async <T>(url: string, body: any): Promise<T> => axios.post(url, body).then((res) => res.data),
    put: async <T>(url: string, body: any): Promise<T> => axios.put(url, body).then((res) => res.data),
    delete: async <T>(url: string): Promise<T> => axios.delete(url).then((res) => res.data),
  };
};

E, em vez de modificar useFetch, criar hooks específicos para cada ação, como usePost:

const usePost = <T>(url: string, body: any): FetchResult<T> => {
  const [data, setData] = useState<T | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);
  const http: IHttp = Http();

  const postData = () => {
    setIsLoading(true);
    http.post<T>(url, body)
      .then((response) => setData(response))
      .catch(() => setError("Erro ao enviar dados!"))
      .finally(() => setIsLoading(false));
  };

  return { data, isLoading, error, postData };
};

Isso mantém a responsabilidade única e evita forçar métodos desnecessários.

Perfeito, obrigado pelos esclarecimentos. Em cada hook individual, seria como se fosse um useCase específico: create-category, get-categories, etc.