Crei um ultils para simular um back end usando o local storage
Published: 2023-12-05 15:17:13

Absurdo, não é? Eu preciso simular um back-end porque, sendo um desenvolvedor full stack, ainda não criei meu próprio back-end para a minha aplicação. Problemas, não é mesmo?

Devido a essa pequena complicação, eu comecei a adiantar os métodos que, no futuro, seriam responsáveis por fazer as requisições para o back-end. Assim, mesmo sem esses endpoints, eu poderia avançar no desenvolvimento do front-end para depois conectar aos endpoints.

Não é a primeira vez que faço isso, então eu já sabia o que estava fazendo.

**Primeiro, aqui está o utilitário que criei:**

```
import generateHashId from './generateHashId';

type localStorageBaseType = {
  id: string;
  created_at: Date;
};

export class NotFoundError extends Error {
  constructor(message: string) {
    super(message);
    this.message = message;
  }
}

export class StorageError extends Error {
  constructor(message: string) {
    super(message);
    this.message = message;
  }
}

class LocalStorageUtil<T extends localStorageBaseType> {
  private key: string;

  constructor(key: string) {
    this.key = key;
  }

  // Obtém os dados do Local Storage para a chave especificada
  getData(): T[] {
    const data = localStorage.getItem(this.key);
    return data ? JSON.parse(data) : [];
  }

  getById(id: string): T | undefined {
    const data = this.getData();
    return data.find((item) => item.id === id);
  }
  // Salva os dados no Local Storage para a chave especificada
  saveData(data: T[]): void {
    localStorage.setItem(this.key, JSON.stringify(data));
  }

  updateItem(item: T): void {
    const data = this.getData();
    const findIndex = data.findIndex((i) => i.id === item.id);

    if (findIndex === -1) {
      throw new NotFoundError('Item not found');
    }

    if (findIndex !== -1) {
      data[findIndex] = item;
      this.saveData(data);
    }
  }

  // Adiciona um novo item aos dados existentes
  addItem(item: Omit<T, 'id' | 'created_at'>): void {
    if (!item) {
      throw new StorageError('data is required');
    }

    const data = this.getData();
    const newItem: T = {
      id: generateHashId(16),
      created_at: new Date(),
      ...item
    } as T;
    data.push(newItem);
    this.saveData(data);
  }

  // Remove um item específico dos dados
  removeItem(id: string): void {
    const data = this.getData();
    const filteredData = data.filter((item) => item.id !== id);
    this.saveData(filteredData);
  }

  // Remove todos os dados relacionados à chave especificada
  deleteData(): void {
    localStorage.removeItem(this.key);
  }
}

export default LocalStorageUtil;
```

Como pode ver, é uma classe que de dar alguns métodos, os principais de um **CRUD**. E o uso dela é bem simples, como pode ver, esta usando typescript o que já ajuda bastante.

**Primeiro passo: instanciando a casse** 

Como ela é uma classe, precisamos instanciar ela em algum lugar, ai ficar sua vontade

```

const keys = {
  budgets: '@budgets'
};

export type Budgets = {
  name: string;
  value: number;
} & localStorageBaseType;


const budgetStorage = new LocalStorageUtil<Budgets>(keys.budgets);

export { budgetStorage };
```

O que é esse localStorageBaseType?  é somente um tipo base para você da merge com o tipo que vc quer passar para a classe, ela vai usar para ajudar na tipagem dos metodos.

ela por baixo dos planos tem **id** e um **created_at** para ajudar nos métodos da classe de buscar e update. 

**Segundo passo: finalmente usando**

O uso ficar bem fácil, é so pegar **budgetStorage** e começar usar os métodos.

```

budgetStorage.addItem({
  name: 'Salário',
  value: 1000
});

const budgets = budgetStorage.getData() 
// spec: {
// name: 'Salário', 
// value: 1000
// id: 'x1y2z3',
// created_at: '17/12/2023'
// }

budgetStorage.updateItem({
  name: 'Salário',
  id: 'x1y2z3',
  value: 2000,
  created_at: new Date()
});

// Para atualizar é so passar o item com o update que o
// metodo vai buscar pelo id para atualizar o item
```
Os outros métodos são bem fáceis de usar e com a ajuda o typescript, temos o removeItem, deleteData, getById. 

lembrando que foi uma solução bem simples para ajudar a completar um etapa do projeto e claro que da pra melhorar. é isso.