@otempo/search
v1.1.1
Published
Biblioteca Node.js
Maintainers
Readme
🗞️ O Tempo Search
Uma biblioteca Node.js moderna e tipada para integração com a API de pesquisa da O Tempo, oferecendo funcionalidades de busca com sugestões em tempo real.
✨ Características
- 🔍 Pesquisa em tempo real com sugestões automáticas
- 📄 Paginação completa com navegação entre páginas
- ⚡ Debounce inteligente para otimizar requisições
- 📊 Estatísticas de pesquisa com análises detalhadas
- 🏷️ Filtros por categoria (versal)
- 🔧 Configuração flexível com timeouts e headers customizados
- 📝 TypeScript completo com tipos bem definidos
- 🚀 Performance otimizada com axios
- 🛡️ Tratamento de erros robusto
📦 Instalação
Via NPM (Recomendado)
npm install @otempo/searchVia CDN (Navegador)
<!-- Carregando via unpkg -->
<script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
<script src="https://unpkg.com/@otempo/search@latest/dist/otempo-search.umd.min.js"></script>
<!-- Ou via jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@otempo/search@latest/dist/otempo-search.umd.min.js"></script>🚀 Uso Rápido
Pesquisa Básica
const { search } = require('otempo-search');
// Pesquisa simples
const resultados = await search('bomba');
console.log(`Encontrados ${resultados.meta.count} resultados`);Com TypeScript
import { search, SearchResponse } from '@otempo/search';
const resultados: SearchResponse = await search('guerra');
resultados.data.forEach(item => {
console.log(`${item.titulo} - ${item.versal}`);
});Via CDN (Navegador)
// Após carregar os scripts, a biblioteca fica disponível globalmente
const resultados = await window.OtempoSearch.search('tecnologia');
console.log(`Encontrados ${resultados.meta.count} resultados`);
// Usando funções helper
const sugestoes = await window.OtempoSearch.getSuggestions('politica', 5);
// Criando instância customizada
const cliente = new window.OtempoSearch.OtempoSearch({
clientId: 'meu-app-123',
searchIndex: 'news-index'
});📚 Exemplos Detalhados
🔑 Client ID
A biblioteca suporta o envio de um Client ID em todas as requisições para identificação e rastreamento. O ID é enviado como header X-Client-ID.
// Configurando clientId na instância
const cliente = new OtempoSearch({
clientId: 'meu-app-123'
});
// Todas as requisições incluirão o clientId
const resultados = await cliente.search('tecnologia');
// Ou passando clientId por chamada específica
const resultados2 = await cliente.search('esportes', {
clientId: 'app-esportes-456'
});
// Com funções helper
const sugestoes = await getSuggestions('politica', 5, {
clientId: 'app-politica-789'
});🔍 Search Index
A biblioteca suporta o envio de um Search Index como query parameter para especificar qual índice de pesquisa usar. O índice é enviado como parâmetro searchIndex na URL.
// Configurando searchIndex na instância
const cliente = new OtempoSearch({
searchIndex: 'news-index'
});
// Todas as requisições incluirão o searchIndex
const resultados = await cliente.search('tecnologia');
// Ou passando searchIndex por chamada específica
const resultados2 = await cliente.search('esportes', {
searchIndex: 'sports-index'
});
// Com funções helper
const sugestoes = await getSuggestions('politica', 5, {
searchIndex: 'politics-index'
});
// Combinando clientId e searchIndex
const clienteCompleto = new OtempoSearch({
clientId: 'meu-app-123',
searchIndex: 'main-index'
});1. Pesquisa com Opções
const { OtempoSearch } = require('otempo-search');
const cliente = new OtempoSearch({
timeout: 10000,
headers: {
'X-Custom-Header': 'meu-app'
}
});
const resultados = await cliente.search('política', {
limit: 10
});1.1. Pesquisa com Client ID
const { OtempoSearch } = require('otempo-search');
// Configurando clientId na instância
const cliente = new OtempoSearch({
clientId: 'meu-app-123',
timeout: 10000
});
// Todas as requisições deste cliente incluirão o clientId
const resultados = await cliente.search('tecnologia');
// Ou passando clientId por chamada
const resultados2 = await cliente.search('esportes', {
clientId: 'app-esportes-456',
limit: 10
});2. Sugestões em Tempo Real
const { getSuggestions } = require('otempo-search');
// Busca 5 sugestões para "economia"
const sugestoes = await getSuggestions('economia', 5);
sugestoes.forEach(sugestao => {
console.log(sugestao.titulo);
});
// Com clientId
const sugestoesComId = await getSuggestions('politica', 5, {
clientId: 'app-politica-789'
});3. Pesquisa com Debounce
const { OtempoSearch } = require('otempo-search');
const cliente = new OtempoSearch();
// Simula digitação do usuário
cliente.searchWithDebounce('tecnologia', (response) => {
console.log(`📊 ${response.meta.totalResults} resultados encontrados`);
console.log(`📄 Página ${response.meta.page} de ${response.meta.totalPages}`);
// Acessa os resultados
response.data.forEach(item => {
console.log(`- ${item.titulo} (${item.versal})`);
});
// Verifica paginação
if (response.meta.hasNextPage) {
console.log('⏭️ Tem próxima página');
}
}, 300); // 300ms de delay4. Filtros por Categoria
const { OtempoSearch } = require('otempo-search');
const cliente = new OtempoSearch();
// Busca apenas notícias de esporte
const noticiasEsporte = await cliente.searchByCategory('ESPORTE');5. Estatísticas da Pesquisa
const { OtempoSearch } = require('otempo-search');
const cliente = new OtempoSearch();
const stats = await cliente.getSearchStats('cultura');
console.log(`Total: ${stats.totalResults}`);
console.log(`Média de caracteres: ${stats.averageTitleLength}`);
console.log('Categorias:', stats.categories);6. Paginação
const { search, getNextPage, getPage, getPaginationInfo } = require('otempo-search');
// Pesquisa com paginação
const resultado = await search('hugo', { limit: 5, page: 1 });
console.log(`Página ${resultado.meta.page} de ${resultado.meta.totalPages}`);
// Buscar próxima página
if (resultado.meta.hasNextPage) {
const proximaPagina = await getNextPage('hugo', resultado.meta.page, { limit: 5 });
console.log(`Próxima página: ${proximaPagina.data.length} resultados`);
}
// Buscar página específica
const pagina2 = await getPage('hugo', 2, { limit: 5 });
// Obter informações de paginação
const info = await getPaginationInfo('hugo', { limit: 10 });
console.log(`Total: ${info.totalResults}, Páginas: ${info.totalPages}`);🔧 API Reference
Classe OtempoSearch
Construtor
new OtempoSearch(config?: OtempoSearchConfig)Configurações:
baseURL?: string- URL base da API (padrão:https://searchapi.otempo.com.br/api)timeout?: number- Timeout em ms (padrão:5000)headers?: Record<string, string>- Headers customizadosshowSuggestions?: boolean- Mostrar dropdown de sugestões por padrão (padrão:true)showSuggestionsInResults?: boolean- Mostrar sugestões na lista por padrão (padrão:false)clientId?: string- ID do cliente para incluir em todas as requisições (enviado como headerX-Client-ID)searchIndex?: string- Índice de pesquisa para incluir como query parameter
Métodos
search(query: string, options?: SearchOptions): Promise<SearchResponse>
Realiza uma pesquisa na API.
Parâmetros:
query: string- Termo de pesquisa (mínimo 2 caracteres)options?: SearchOptions- Opções da pesquisa
Opções:
limit?: number- Número máximo de resultadospage?: number- Número da página (padrão: 1)timeout?: number- Timeout específico para esta requisiçãoheaders?: Record<string, string>- Headers específicosshowSuggestions?: boolean- Mostrar dropdown de sugestões (padrão: true)showSuggestionsInResults?: boolean- Mostrar sugestões na lista de resultados (padrão: false)clientId?: string- ID do cliente para incluir nesta requisição (enviado como headerX-Client-ID)searchIndex?: string- Índice de pesquisa para incluir como query parameter
Observações:
- A query deve ter pelo menos 2 caracteres para otimizar o uso da API
searchWithDebounce(query: string, callback: Function, delay?: number, options?: SearchOptions): void
Realiza pesquisa com debounce para sugestões em tempo real.
Parâmetros:
query: string- Termo de pesquisacallback: (response: SearchResponse) => void- Função de callback com resposta completa (incluindo metadados de paginação)delay?: number- Delay em ms (padrão:300)options?: SearchOptions- Opções da pesquisa
Observações:
- O callback recebe a resposta completa da API, incluindo metadados de paginação
- Para acessar apenas os resultados, use
response.data - Para acessar os metadados, use
response.meta
getSuggestions(query: string, maxSuggestions?: number, options?: SearchOptions): Promise<SearchResult[]>
Busca sugestões para um termo.
Parâmetros:
query: string- Termo de pesquisa (mínimo 2 caracteres)maxSuggestions?: number- Máximo de sugestões (padrão:5)options?: SearchOptions- Opções da pesquisa
searchByCategory(versal: string, options?: SearchOptions): Promise<SearchResult[]>
Busca notícias por categoria específica.
getSearchStats(query: string, options?: SearchOptions): Promise<SearchStats>
Obtém estatísticas da pesquisa.
cancelSearch(): void
Cancela a pesquisa com debounce pendente.
getNextPage(query: string, currentPage: number, options?: SearchOptions): Promise<SearchResponse>
Busca a próxima página de resultados.
Parâmetros:
query: string- Termo de pesquisa originalcurrentPage: number- Página atualoptions?: SearchOptions- Opções da pesquisa
getPrevPage(query: string, currentPage: number, options?: SearchOptions): Promise<SearchResponse>
Busca a página anterior de resultados.
Parâmetros:
query: string- Termo de pesquisa originalcurrentPage: number- Página atualoptions?: SearchOptions- Opções da pesquisa
Observações:
- Lança erro se tentar buscar página anterior à primeira
getPage(query: string, page: number, options?: SearchOptions): Promise<SearchResponse>
Busca uma página específica de resultados.
Parâmetros:
query: string- Termo de pesquisapage: number- Número da páginaoptions?: SearchOptions- Opções da pesquisa
Observações:
- Lança erro se o número da página for menor que 1
getAllPages(query: string, options?: SearchOptions): Promise<SearchResult[]>
Obtém todas as páginas de resultados para uma pesquisa.
Parâmetros:
query: string- Termo de pesquisaoptions?: SearchOptions- Opções da pesquisa
Observações:
- Busca automaticamente todas as páginas disponíveis
- Inclui limite de segurança de 100 páginas para evitar loops infinitos
getPaginationInfo(query: string, options?: SearchOptions): Promise<PaginationInfo>
Obtém informações de paginação para uma pesquisa.
Parâmetros:
query: string- Termo de pesquisaoptions?: SearchOptions- Opções da pesquisa
Retorna:
{
currentPage: number;
totalPages: number;
totalResults: number;
hasNextPage: boolean;
hasPrevPage: boolean;
resultsPerPage: number;
}Funções Helper
search(query: string, options?: SearchOptions): Promise<SearchResponse>
Função helper para pesquisa rápida usando instância padrão.
getSuggestions(query: string, maxSuggestions?: number, options?: SearchOptions): Promise<SearchResult[]>
Função helper para sugestões rápidas.
getNextPage(query: string, currentPage: number, options?: SearchOptions): Promise<SearchResponse>
Função helper para buscar próxima página.
getPrevPage(query: string, currentPage: number, options?: SearchOptions): Promise<SearchResponse>
Função helper para buscar página anterior.
getPage(query: string, page: number, options?: SearchOptions): Promise<SearchResponse>
Função helper para buscar página específica.
getAllPages(query: string, options?: SearchOptions): Promise<SearchResult[]>
Função helper para obter todas as páginas.
getPaginationInfo(query: string, options?: SearchOptions): Promise<PaginationInfo>
Função helper para obter informações de paginação.
📊 Tipos TypeScript
SearchResult
interface SearchResult {
titulo: string; // Título da notícia
versal: string; // Categoria/versal
bigode: string; // Resumo/descrição
imagem: string; // URL da imagem
path: string; // Caminho/URL da notícia
}SearchResponse
interface SearchResponse {
success: boolean; // Sucesso da requisição
data: SearchResult[]; // Array de resultados
meta: SearchMeta; // Metadados da pesquisa
}SearchMeta
interface SearchMeta {
query: string; // Query executada
count: number; // Total de resultados
limit: number; // Limite por página
page: number; // Página atual
totalPages: number; // Número total de páginas
totalResults: number; // Número total de resultados
hasNextPage: boolean; // Indica se existe próxima página
hasPrevPage: boolean; // Indica se existe página anterior
timestamp: string; // Timestamp da resposta
}🛠️ Desenvolvimento
Instalação das Dependências
npm installCompilação
npm run buildDesenvolvimento com Watch
npm run devTestes
npm testLinting
npm run lint📦 Publicação
Configuração do Azure Artifacts
Este pacote é publicado no Azure Artifacts. Para configurar a autenticação localmente:
Gerar um Personal Access Token (PAT) com permissões de Packaging (Read & Write)
Configurar a variável de ambiente:
export AZURE_PAT='seu_pat_aqui'Testar a autenticação:
./scripts/test-auth.shPublicar o pacote:
npm run publish:azure
Pipeline de CI/CD
O projeto usa Azure DevOps Pipeline para publicação automática. O pipeline:
- Executa testes e linting
- Compila o código TypeScript
- Publica automaticamente no Azure Artifacts quando há commits na branch
master
Estrutura do Feed
- Registry:
https://pkgs.dev.azure.com/gruposada/0ac0f368-01b8-4a03-8223-f071ef20141a/_packaging/Otempo-Search/npm/registry/ - Escopo:
@otempo - Nome do pacote:
@otempo/search
🎨 Frontend de Teste
Para testar a biblioteca de forma interativa, você pode usar o frontend incluído:
Iniciar o Frontend
# Usando npm script (recomendado)
npm run frontend
# Ou navegando para a pasta
cd frontend && node server.jsAcessar o Frontend
Abra seu navegador e acesse: http://localhost:3000
Funcionalidades do Frontend
- 🔍 Pesquisa em tempo real com sugestões automáticas
- 💡 Sugestões inteligentes que aparecem enquanto você digita
- 📊 Estatísticas detalhadas dos resultados da pesquisa
- 🎨 Interface moderna e responsiva
- ⚡ Performance otimizada com debounce
Para mais detalhes, consulte o README do Frontend.
📁 Estrutura do Projeto
otempo_search/
├── src/
│ ├── types/
│ │ └── index.ts # Definições de tipos
│ ├── OtempoSearch.ts # Classe principal
│ └── index.ts # Exports principais
├── examples/
│ ├── basic-usage.js # Exemplos JavaScript
│ └── typescript-usage.ts # Exemplos TypeScript
├── frontend/ # Frontend de teste
│ ├── index.html # Página principal
│ ├── app.js # Lógica da aplicação
│ ├── server.js # Servidor Node.js
│ └── README.md # Documentação do frontend
├── tests/ # Testes unitários
│ ├── setup.ts # Configuração dos testes
│ └── OtempoSearch.test.ts # Testes da biblioteca
├── dist/ # Código compilado
├── package.json
├── tsconfig.json
└── README.md🌐 Uso via CDN
A biblioteca está disponível via CDN para uso direto no navegador, sem necessidade de instalação via NPM.
URLs dos CDNs
unpkg:
https://unpkg.com/@otempo/search@latest/dist/otempo-search.umd.min.js
jsdelivr:
https://cdn.jsdelivr.net/npm/@otempo/search@latest/dist/otempo-search.umd.min.js
Exemplo Completo
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>O Tempo Search - Exemplo CDN</title>
</head>
<body>
<h1>🗞️ O Tempo Search</h1>
<input type="text" id="searchInput" placeholder="Digite sua pesquisa...">
<button onclick="search()">🔍 Pesquisar</button>
<div id="results"></div>
<!-- Carregando a biblioteca via CDN -->
<script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
<script src="https://unpkg.com/@otempo/search@latest/dist/otempo-search.umd.min.js"></script>
<script>
async function search() {
const query = document.getElementById('searchInput').value;
try {
const results = await window.OtempoSearch.search(query);
document.getElementById('results').innerHTML =
`<p>Encontrados ${results.meta.count} resultados</p>`;
} catch (error) {
console.error('Erro:', error);
}
}
</script>
</body>
</html>Funcionalidades Disponíveis via CDN
- ✅ Pesquisa básica:
window.OtempoSearch.search(query, options) - ✅ Sugestões:
window.OtempoSearch.getSuggestions(query, maxSuggestions, options) - ✅ Paginação:
window.OtempoSearch.getPage(query, page, options) - ✅ Instância customizada:
new window.OtempoSearch.OtempoSearch(config) - ✅ Todas as funções helper disponíveis no objeto global
Exemplos de Uso via CDN
// Pesquisa básica
const results = await window.OtempoSearch.search('tecnologia');
// Com configurações
const results = await window.OtempoSearch.search('esportes', {
limit: 10,
clientId: 'meu-app-123',
searchIndex: 'news-index'
});
// Sugestões
const suggestions = await window.OtempoSearch.getSuggestions('politica', 5);
// Instância customizada
const client = new window.OtempoSearch.OtempoSearch({
clientId: 'custom-app',
timeout: 10000
});Exemplos Prontos
🔗 Endpoint da API
A biblioteca consome o endpoint:
https://searchapi.otempo.com.br/api/search?q={query}Resposta esperada:
{
"success": true,
"data": [
{
"titulo": "Título da notícia",
"versal": "CATEGORIA",
"bigode": "Resumo da notícia",
"imagem": "/path/to/image.jpg",
"path": "/path/to/news"
}
],
"meta": {
"query": "termo pesquisado",
"count": 1,
"limit": 20,
"page": 1,
"totalPages": 1,
"totalResults": 1,
"hasNextPage": false,
"hasPrevPage": false,
"timestamp": "2025-07-02T11:52:18.510Z"
}
}🤝 Contribuindo
- Fork o projeto
- Crie uma branch para sua feature (
git checkout -b feature/AmazingFeature) - Commit suas mudanças (
git commit -m 'Add some AmazingFeature') - Push para a branch (
git push origin feature/AmazingFeature) - Abra um Pull Request
📄 Licença
Este projeto está licenciado sob a Licença MIT - veja o arquivo LICENSE para detalhes.
🆘 Suporte
Se você encontrar algum problema ou tiver dúvidas, por favor abra uma issue.
Desenvolvido com ❤️ para a comunidade de desenvolvedores brasileiros.
