Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/laravieira/weather

Brazilian weather fetcher with React, shows current weather and provisions 2 weeks ahead.
https://github.com/laravieira/weather

climatempo weather weather-api weather-forecast

Last synced: 3 days ago
JSON representation

Brazilian weather fetcher with React, shows current weather and provisions 2 weeks ahead.

Awesome Lists containing this project

README

        

[![Test](https://github.com/laravieira/weather/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/laravieira/weather/actions/workflows/test.yml)
[![AWS Worker](https://github.com/laravieira/weather/actions/workflows/worker.yml/badge.svg)](https://github.com/laravieira/weather/actions/workflows/worker.yml)
![CloudFlare Pages Weather](https://img.shields.io/endpoint?url=https://cloudflare-pages-badges.laravieira.workers.dev/?projectName=weather)



Climatempo

___



Video

___

- [Versão em inglês](README.md)

### Skills
- [x] HTML5/CSS3/Javascript
- [x] React.js/Typescript/ES-6/JSX
- [x] API Node.js/Typescript/REST
- [x] Docker
- [x] Responsividade
- [x] Pesquisa autocompleta dinâmica
- [x] 1 cartão para cada provisão meteorológica diária
- [x] FE/BE Validação de entrada do usuário
- [x] Cache (para salvar a personalização)
- [x] Uso do Elasticsearch como banco de dados
- [x] Testes unitários com Jest
- [x] Boas práticas de código/design
- [x] Página com acessibilidade
- [x] Uso de dados reais atualizados
- [x] Desempenho de pesquisa aprimorado com filtragem no cliente
- [ ] Arruma minha cama

### Como executar usando o Docker
Vá para o diretório raiz do desafio e execute:
```shell
docker-compose up
```
ou, se você tiver npm disponível:
```shell
npm run docker
```

##### Endpoints:
- [`http://localhost:3000`](http://localhost:3000) -> Página web
- [`http://localhost:4000`](http://localhost:4000) -> API REST
- [`http://localhost:9200`](http://localhost:9200) -> Elasticsearch

### Como executar localmente
###### Requisitos
* Elastic search ^8 instalado sem TLS
* Node.js ^19 instalado
* npm ^8 instalado

Defina as seguintes variáveis de ambiente
* `ELASTIC_HOST=[elastic address with port]`
* `ELASTIC_USER=[elastic user]`
* `ELASTIC_PASSWORD=[elastic password]`

Você pode criar um arquivo `.env` na pasta `/server` para declarar essas variáveis.

Vá para o diretório raiz do desafio e execute:
```shell
npm install
npm start
```

##### Endpoints:
- [`http://localhost:3000`](http://localhost:3000) -> Página web
- [`http://localhost:4000`](http://localhost:4000) -> API REST

### Como executar testes
Vá para o diretório raiz do desafio e execute:
```shell
npm install
npm run test
```
Para testar somente servidor, use:
```shell
npm run test:server
```
Para testar somente web, use:
```shell
npm run test:web
```

## Abordagem
#### Server
Primeiro comecei a entender os [dados fictícios](base) oferecidos no repositório. Como os dados estavam muito desatualizados comecei a pesquisar se os dados estavam disponíveis publicamente, descubro a [API Clima Tempo Advisor](https://advisor.climatempo.com.br/), que permitia apenas a busca limitada de uma cidade por token por 24hs.

Eu vi que o [site Clima Tempo](https://www.climatempo.com.br/) oferece gratuitamente o clima de qualquer cidade na base, então decidi implementar o *web scrapping* para coletar dados climáticos dinamicamente. Isso é o que [`ClimaTempo.engine`](server/src/Engines/ClimaTempo/ClimaTempo.engine.ts) faz.

Então o [dados fictícios usados](server/src/dummy.json) foram atualizados com dados reais do período de 26/11/2022 a 10/12/2022 com as seguintes cidades:

- Osasco, SP (Brasil) *
- São Paulo, SP (Brasil) *
- Juiz de Fora, MG (Brasil) **
- Chácara, MG (Brasil) **
- Fortaleza, CE (Brasil)
- Gramado, RS (Brasil)
- Porto de Galinhas, PE (Brasil)
- Rio de Janeiro, RJ (Brasil)
- Curitiba, PR (Brasil)
- Arraial do Cabo, RJ (Brasil)
- Natal, RN (Brasil)
- Campos do Jordão, SP (Brasil)
- Belo Horizonte, MG (Brasil)
- Angra dos Reis, RJ (Brasil)

###### * Cidade obrigatória no desafio
###### ** Cidades que frequento

Quando o servidor é iniciado pela primeira vez, os dados fictícios são indexados no elasticsearch para estarem disponíveis para a pesquisa pelo usuário.

O servidor encadiará automaticamente qualquer solicitação ao mecanismo ClimaTempo e indexará a resposta, fazendo com que o elasticsearch atue como um cache. Se o elasticsearch já tiver os dados, ele será enviado rapidamente para o cliente e posteriormente desencadiará o mecanismo ClimaTempo para atualizar os dados do elasticsearch.

##### Os endpoints disponíveis são:
```shell
GET /search/[string] # para pesquisar cidades pelo nome
GET /ping # Para fazer ping-pong no servidor
GET /city/[id] # Para obter informações básicas da cidade
GET /city/[id]/now # Para obter o clima atual
GET /city/[code]/weather # Para obter o clima do dia atual
GET /city/[code]/weathers # Para obter o clima do dia atual e os próximos 14 dias
```

#### Frontend
O frontend está usando o kit de design [MUI](https://mui.com/) e [Tailwindcss](https://tailwindcss.com/) para estilo, ele foi projetado de forma responsiva para desktop, tablet e celular. No cabeçalho você pode:
* Pesquisar a cidade com opções dinâmicas de preenchimento automático
* Alternar entre o modo escuro e claro (primeiro seguirá o padrão do sistema e a opção de cache se você alterá-lo manualmente)
* Alternar entre as unidades °C e °F (o padrão é °C, ele armazena em cache se você alterá-lo manualmente)
* Alternar entre unidades de *mm* e *polegadas* (o padrão é *mm*, ele armazena em cache se você o alterar manualmente)

### O formato de dados do web scraping:

###### [Informações básicas da cidade](server/src/Models/Locale.model.ts)
```yaml
id: número # O id da cidade
name: string # O nome da cidade
uf: string # O estado da cidade
city: number # Código da cidade
region: string # A região da cidade
acrônimo: string # Sigla do país da cidade
```

###### [Informações detalhadas da cidade](server/src/Models/DetailedLocale.model.ts)
```yaml
idlocale: number # O id da cidade
idcity: number # Código da cidade
capital: boolean # Se a cidade for uma capital
idcountry: number # O id do país
ac: string # A sigla do país
country: string # O nome do país
uf: string # O estado da cidade
city: string # O nome da cidade
region: string # A região da cidade
seaside: boolean # Se for uma cidade litorânea
latitude: number # Latitude da cidade
longitude: number # A longitude da cidade
tourist: boolean # Se for uma cidade turística
agricola: boolean # Se for uma cidade agricola
base: string # Parece o nome da coleção da cidade
searchPoints: number # Qual a probabilidade desejada
```

###### [Informações meteorológicas instantâneas](server/src/Models/InstantWeather.model.ts)
```yaml
idlocale: number # O id da cidade
temperatura: number # A temperatura atual
icon: string # O alias para ícones do tempo
condição: string # Uma descrição do clima atual
umidade: number # O nível de umidade atual
sensação: number # A sensação de temperatura atual
windVelocity: number # A velocidade atual do vento
pressão: number # A pressão atmosférica atual
date: string # A data e hora desta informação meteorológica
```

###### [Informações meteorológicas diárias](server/src/Models/DailyWeather.model.ts)
```yaml
idcity: number # Código da cidade
moon: string[] # Lista de luas do dia
rainbow: string # A descrição da probabilidade de um arco-íris
description: string # Currículo do clima do dia
data: string # A data do dia
temperatura:
min: number # A temperatura mínima do dia
max: number # A temperatura máxima do dia
chuva:
precipitação: number # Precipitação de chuva do dia
probabilidade: number # O dia está chovendo provavelmente
vento:
bússola: string # A direção do vento em cartesiano
velocidade: number # A velocidade média do vento
umidade:
min: number # A umidade mínima do dia
max: number # A umidade máxima do dia
Sol:
manhã: string # A hora do sol
tarde: string # A hora do nascer do sol
```