Skip to main content

Zero-dep client for the Hacker News Firebase API.

Project description

hacker-news-client

One design contract. Six idiomatic libraries. Zero surprises.

A production-quality client suite for the official Hacker News Firebase API — JavaScript, TypeScript, Python, Ruby, Go, and Rust — sharing one wire contract, one mock server, one fixture set, and one cross-language verification harness.


License: MIT Version CI Lint CodeQL Scorecard Supply chain Codecov Tests Conventional Commits Contributor Covenant


Languages

Node Python Ruby Go Rust


Quick-start  ·  Architecture  ·  Design contract  ·  Research  ·  Contribute  ·  Changelog  ·  Security


Why this exists

  • Idiomatic, not uniform. Every library feels native to its language — JS uses fetch + AbortController, Rust uses tokio + reqwest, Go uses context.Context + tagged interface, Python uses @dataclass + match — but they all implement the same conceptual API against the same wire protocol.
  • Zero runtime dependencies where the stdlib can do the job. Only Rust ships dependencies (tokio, reqwest, serde, thiserror) because those are the de-facto ecosystem baseline.
  • Test-first, cross-language. A shared Node-based mock server and fixture set drive byte-identical behavior checks across every library.

Table of contents


Feature matrix

Capability JS TS Python Go Ruby Rust
Single-item fetch
Batch fetch with bounded concurrency, order-preserving
Fail-fast on first batch error
Discriminated / tagged item types JSDoc union dataclass interface subclass enum
All six *_story_ids + hydrated *_stories(limit)
Recursive comment_tree with deleted-node pruning
User profile fetch
max_item, updates (typed record)
10s total timeout, budget enforced end-to-end
Injectable transport for tests / middleware
Doc comments on every public symbol JSDoc TSDoc Google godoc YARD rustdoc
Strict-mode linter Biome Biome ruff go vet+gofmt RuboCop clippy+fmt

Quick-start

JavaScript (Node 20+)
npm install hacker-news-client
import { HackerNewsClient } from 'hacker-news-client';

const client = new HackerNewsClient();
const story = await client.item(1);
console.log(story?.title);

const top = await client.topStories(10);
const tree = await client.commentTree(8863);

More: js/README.md

TypeScript (Node 22.6+, strict)
npm install @hacker-news/client-ts
import { HackerNewsClient, type Item } from '@hacker-news/client-ts';

const client = new HackerNewsClient();
const item = await client.item(1);
if (item?.type === 'story') {
  console.log(item.title, item.score);
}

More: ts/README.md

Python (3.10+)
pip install hacker-news-client
from hacker_news_client import HackerNewsClient, Story

client = HackerNewsClient()
item = client.item(1)

match item:
    case Story(title=t, by=b, score=s):
        print(f"{t}{b} ({s})")

More: python/README.md

Ruby (3.1+)
gem install hacker-news-client
require 'hacker/news/client'

client = Hacker::News::Client.new
item = client.item(1)
puts item.title if item.is_a?(Hacker::News::Story)

More: ruby/README.md

Go (1.22+)
go get github.com/hammadxcm/hacker-news-client/go
import (
    "context"
    "fmt"
    hackernews "github.com/hammadxcm/hacker-news-client/go"
)

c := hackernews.New(hackernews.Options{})
item, err := c.Item(context.Background(), 1)
if err != nil { /* handle */ }
if s, ok := item.(hackernews.Story); ok {
    fmt.Println(s.Title)
}

More: go/README.md

Rust (2021, tokio)
cargo add hacker-news-client
use hacker_news_client::{HackerNewsClient, Item, Options};

# #[tokio::main]
# async fn main() -> hacker_news_client::Result<()> {
let client = HackerNewsClient::new(Options::default())?;
if let Some(Item::Story(s)) = client.item(1).await? {
    println!("{}", s.title.unwrap_or_default());
}
# Ok(()) }

More: rust/README.md


Repository layout

hacker-news-client/
├── README.md            ← you are here
├── CONTRIBUTING.md      ← how to contribute
├── CODE_OF_CONDUCT.md   ← Contributor Covenant 2.1
├── SECURITY.md          ← vulnerability disclosure
├── CHANGELOG.md         ← versioned release notes
├── SUPPORT.md           ← where to get help
├── LICENSE              ← MIT
├── VERSION              ← single source of truth, "0.1.0"
├── RESEARCH.md          ← API reference + prior-art survey
├── DESIGN.md            ← locked cross-language contract
├── docs/
│   └── ARCHITECTURE.md  ← contributor-facing system overview
├── js/      → idiomatic ESM JavaScript client
├── ts/      → strict TypeScript client with tagged unions
├── python/  → stdlib + optional httpx async extra
├── ruby/    → stdlib Net::HTTP gem
├── go/      → stdlib net/http + context.Context
├── rust/    → tokio + reqwest + serde
├── test/    → shared mock server + JSON fixtures
│   ├── mock-server.js
│   └── fixtures/*.json
├── scripts/
│   ├── verify.sh        ← cross-language test matrix
│   └── bump-version.sh
└── .github/             ← CI workflows, issue/PR templates

Development

Two-command onboarding:

npm install            # installs husky + eslint + prettier + c8 at the root
npm test               # runs scripts/verify.sh — all six language suites

Per-language iteration:

npm run lint           # Biome, ruff, rubocop, go vet+gofmt, clippy, cargo fmt
npm run coverage       # generates coverage reports per language
node --test test/*.test.js                   # mock server only
cd js     && node --test test/*.test.js      # js unit + integration
cd python && python3 -m unittest discover    # python
cd ruby   && rake test                       # ruby
cd go     && go test ./...                   # go
cd rust   && cargo test                      # rust

A Husky pre-commit hook runs lint-staged on touched files plus a mock-server smoke test. A pre-push hook runs the full cross-language verification harness.


Coverage

Measured per language in CI and locally via npm run coverage:

Language Line Branch Tool
JavaScript 100% 100% c8
TypeScript 100% 100% c8
Python 100% coverage.py
Go 98.3% go test -cover
Ruby 100% 96.96% SimpleCov
Rust 94.4% cargo-llvm-cov

The sub-100% cells are language-tooling quirks: Go's coverage tracer doesn't track inlined no-op tag methods, and Rust has a few concurrency-race branches that aren't deterministically reachable from tests.


Quality and security tooling

Every PR runs through an extensive free-for-OSS tooling stack. Every tool below is free for open-source projects and requires no paid tier or secret.

Tool What it catches
Biome JavaScript + TypeScript lint + format + import sorting (single Rust-based tool; 10–20× faster than ESLint+Prettier)
ruff Python style + correctness (replaces flake8 / isort / pylint)
mypy --strict Python static types
RuboCop Ruby style + correctness
go vet + gofmt Go style + correctness (stdlib)
clippy + rustfmt Rust style + correctness
markdownlint-cli2 Documentation style
actionlint GitHub Actions workflow correctness
shellcheck Shell script bugs + portability
editorconfig-checker Consistent line endings, indentation
CodeQL Semantic security analysis (JS/TS/Python/Ruby/Go)
OSSF Scorecard Open-source best-practices scoring
Dependabot Weekly dependency updates across all ecosystems
dependency-review-action Per-PR diff of new dependencies + CVEs
gitleaks Secret scanning across full git history
npm audit Node.js CVE scanning
pip-audit Python CVE scanning (PyPA)
bundler-audit Ruby CVE scanning (RubySec)
govulncheck Go CVE scanning (official)
cargo-audit Rust CVE scanning (RustSec)
Codecov Per-language coverage upload + PR comments
Husky + lint-staged Local pre-commit + pre-push gates

All of these run automatically on every PR via the workflows under .github/workflows/.


Documentation

Document Audience What it covers
README.md Everyone Overview, quick-start, matrix
docs/ARCHITECTURE.md Contributors How the libraries are organized; how to add a method
DESIGN.md Implementers Locked cross-language contract, type model, error mapping
RESEARCH.md Reviewers Evidence-backed HN API reference, prior-art survey
CHANGELOG.md Users Versioned release notes (Keep a Changelog)
CONTRIBUTING.md Contributors Dev setup, branching, commit convention, PR workflow
SECURITY.md Security researchers Private vulnerability disclosure

Roadmap

v1 is intentionally minimal. The following are reserved extension points (see DESIGN.md §10):

  • client.search.*Algolia HN Search API wrapper (full-text, /items/:id single-call tree).
  • client.updates.stream(...) — Firebase REST SSE for live /updates and /maxitem.
  • client.updates.poll(...) — polling helper that matches the future stream API shape.
  • Retries / rate-limiting / caching middleware — plugs into the already-exposed transport abstraction.
  • Publishing to registries — automated releases via tagged commits.

Want to contribute one of these? See CONTRIBUTING.md.


Contributing

Contributions are welcome and deeply appreciated. Start with CONTRIBUTING.md — it covers dev setup, the monorepo workflow, the commit convention, and what to do when adding a new method (hint: it's six implementations at once).

By participating in this project you agree to abide by our Code of Conduct.


Security

If you've found a vulnerability, please do not open a public issue. Report privately via GitHub Security Advisories. Full policy: SECURITY.md.


Community


License

MIT © hacker-news-client contributors — see LICENSE.


Built with care for every language on the list.

Made with

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hn_api_client-0.1.0.tar.gz (17.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hn_api_client-0.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file hn_api_client-0.1.0.tar.gz.

File metadata

  • Download URL: hn_api_client-0.1.0.tar.gz
  • Upload date:
  • Size: 17.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for hn_api_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 07fe1dfebbf2530461fb5223120f4d707836e759d6970a7f001e746f69d5b0c1
MD5 596a1a9dae62fd00d00352ed80f314e8
BLAKE2b-256 543fad86822370292870e0a6dea9d88909edd5783a9b940463634adaab58d8f7

See more details on using hashes here.

File details

Details for the file hn_api_client-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: hn_api_client-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for hn_api_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dc78e53543444e65e31d58bb57359b5a270b27742ef31fc0f83eebb32936f44a
MD5 c52cafa0d155568be68bedcdad474128
BLAKE2b-256 8ea479fc25ca551739c7cd7aff09b3ead3d9c6ba154763d9faffbdf1bf8ced81

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page