# Disponibilidade de bicicletas em tempo real: como exibir em um aplicativo?

> Exiba a disponibilidade de bicicletas com a API ROOTE: timestamp, frescor, valores desconhecidos, atualização e dados expirados em sua aplicação.

Source: https://www.roote.ai/pt/guides/disponibilidade-bicicletas-tempo-real-exibicao-aplicacao/
Language: pt
Author: ROOTE

Para exibir a disponibilidade de bicicletas em tempo real em um aplicativo, associe o número retornado ao seu frescor e às possibilidades de retirada do veículo. Uma observação descreve o que a fonte sabia em um instante; não garante que uma bicicleta ainda estará disponível na chegada.

O contrato de mobilidade ROOTE distingue estações, veículos individuais e seus estados. A interface deve traduzir essas diferenças sem confundir um valor desconhecido, uma estação vazia e uma fonte temporariamente indisponível.

## Separar uma estação de um veículo individual

Uma estação pode expor contadores de bicicletas e de vagas de retorno. Um veículo individual possui um estado de disponibilidade e outras informações eventuais. Evite contar uma estação como uma bicicleta ou somar contadores representando o mesmo estoque.

No DTO de mobilidade ROOTE, availability.bikes e availability.docks podem ser desconhecidos. Os campos de propulsão ou bateria devem ser exibidos apenas se existirem e forem interpretados conforme o contrato.

[Contrato OpenAPI ROOTE](https://api.roote.ai/openapi.json)

## Ler o frescor e os timestamps

| Campo | Interpretação |
| --- | --- |
| freshness.state | Estado anunciado: fresh, stale, unknown ou static |
| freshness.source_updated_at | Data de atualização da fonte, se conhecida |
| freshness.received_at | Data de recebimento indicada pelo contrato |
| freshness.expires_at | Prazo de validade indicado, se conhecido |
| availability.bikes | Quantidade conhecida ou valor desconhecido |
| pickup.enabled e pickup.state | Informações sobre a retirada de uma bicicleta na estação |

A hora da sua chamada não é automaticamente a da observação. Um resultado recebido às 10h pode conter uma fonte atualizada às 9h45. Não exiba “atualizado agora” com base apenas na hora de recebimento da sua interface.

## Prever estados de exibição distintos

| Dado recebido | Exibição a prever |
| --- | --- |
| Quantidade conhecida e dado fresco | Quantidade observada e indicação temporal |
| Quantidade igual a zero | Nenhuma bicicleta observada, com seu contexto temporal |
| Quantidade null | Disponibilidade desconhecida |
| Estado stale ou prazo vencido | Dado antigo; sugerir uma atualização |
| pickup.enabled=false | Retirada indisponível mesmo se um contador é positivo |
| Erro de busca | Disponibilidade temporariamente indisponível, sem converter para zero |

Não classifique um estado unknown ou static como fresco. Uma informação de estação pode ser estável enquanto o contador evolui rapidamente. Também mantenha os avisos e atribuições exigidos pela resposta.

## Um exemplo de normalização antes da renderização

A função a seguir produz um estado de apresentação a partir de uma estação já validada contra o esquema ROOTE. Ela não é um validador completo da resposta. Os rótulos visíveis devem vir das chaves de tradução da sua interface.

```
function availabilityView(station, now = Date.now()) {
  const freshness = station.freshness;
  const expiresAt = freshness.expires_at
    ? Date.parse(freshness.expires_at) : null;
  const expired = expiresAt !== null &&
    Number.isFinite(expiresAt) && expiresAt <= now;
  if (station.pickup.enabled === false ||
      station.pickup.state === 'unavailable_now') {
    return { state: 'pickup_unavailable', count: null };
  }
  if (expired || freshness.state === 'stale') {
    return { state: 'stale', count: null };
  }
  const count = station.availability.bikes;
  if (freshness.state !== 'fresh' || count === null ||
      !Number.isFinite(count) || count < 0) {
    return { state: 'unknown', count: null };
  }
  return {
    state: count === 0 ? 'empty' : 'observed', count,
    sourceUpdatedAt: freshness.source_updated_at,
    receivedAt: freshness.received_at,
    pickupState: station.pickup.state
  };
}
```

Mesmo com um estado observed, não transforme pickupState=unknown em retirada confirmada. O contador permanece uma observação. Exiba o contexto da retirada se seu produto ajuda o usuário a escolher uma estação.

## Atualizar sem multiplicar chamadas desnecessariamente

Adapte a atualização ao vencimento publicado, às condições do serviço e ao comportamento do usuário. Agrupe pedidos idênticos, evite chamadas em segundo plano em uma página inativa e cancele as de uma busca substituída.

Um tempo local de cache não prova o frescor da fonte. Após um erro, você pode manter a última observação datada se sua interface a apresentar explicitamente como antiga. Não apague essa distinção na primeira retomada bem-sucedida se a fonte continuar stale.

## Entender a ligação com GBFS

GBFS descreve os serviços de mobilidade compartilhada e seus estados publicados. Uma integração direta deve interpretar os arquivos, a versão e os timestamps do fluxo. Com uma API normalizada, use o contrato da API; não adicione um campo GBFS supostamente ausente na sua resposta.

[Escolher entre GTFS, GTFS Realtime e GBFS](https://www.roote.ai/pt/guides/gtfs-gtfs-rt-e-gbfs-quais-diferencas/)

## Testar situações que enganam o leitor

Teste um zero real, um valor desconhecido, um prazo vencido, uma retirada desativada e um erro após um resultado válido. Verifique também os fusos horários de exibição. Um contador positivo jamais deve produzir “bicicleta reservada” e uma indisponibilidade nunca deve produzir um zero inventado.

[Gerenciar respostas vazias e erros](https://www.roote.ai/pt/guides/sem-resultados-ou-erro-api-como-diferenciar/)

[Aplicar essas regras em um assistente IA](https://www.roote.ai/pt/guides/como-criar-um-assistente-que-encontre-mobilidade-ao-redor-de-um-endereco/)

[Guia do usuário para encontrar uma bicicleta](https://www.roote.ai/pt/guides/como-encontrar-uma-bicicleta-de-uso-livre-perto-de-si/)

## Perguntas frequentes

### Uma quantidade positiva garante uma bicicleta na minha chegada?

Não. Ela descreve uma observação, que pode mudar entre a consulta e sua chegada.

### Pode-se substituir null por zero?

Não. null indica um valor desconhecido; zero é uma quantidade conhecida e tem outro significado.

### É preciso atualizar a cada poucos segundos?

Use as indicações de validade, os limites do serviço e as necessidades da sua interface. Uma frequência arbitrária não garante uma fonte mais fresca.
