feat: implement docs-site, legal docs, metrics standard, flux manifests

Closes leeworks-agents/api-company#5  (docs-site Astro scaffold)
Closes leeworks-agents/api-company#9  (metrics instrumentation standard)
Closes leeworks-agents/api-company#10 (Gitea Actions openapi aggregation pipeline)
Closes leeworks-agents/api-company#11 (docs-site Flux HelmRelease)
Closes leeworks-agents/api-company#12 (SEO blog posts x3)
Closes leeworks-agents/api-company#13 (legal docs ToS/Privacy/AUP)
Closes leeworks-agents/api-company#14 (DNS documentation)

## Changes

### docs/legal/
- terms-of-service.md — API usage, liability, account termination, governing law
- privacy-policy.md — request log retention (90d), no PII sold, data sharing
- acceptable-use-policy.md — rate limit abuse, scraping prohibition, resale ban

### docs/metrics-standard.md
- Defines api_requests_total, api_response_duration_seconds, api_data_freshness_seconds
- Fastify (TypeScript) and FastAPI (Python) reference middleware implementations
- Prometheus scrape config and Grafana dashboard guidance

### docs/registry.md
- Decision: use Gitea built-in container registry (no new infra)
- Image naming convention, auth, Kubernetes imagePullSecrets, ingress config

### docs/dns.md
- Required A records for all 6 subdomains
- cert-manager ClusterIssuer and Ingress TLS examples
- Verification commands and human-operator action items

### docs-site/
- Astro 4 + MDX + sitemap scaffold
- Base layout with nav linking all APIs, blog, RapidAPI, status
- Landing page with API cards
- Per-API Redoc viewer pages (zip-enrichment, holidays, air-quality)
- Blog index + 3 SEO blog posts (~1000 words each with JSON-LD)
- Dockerfile (multi-stage: node build + nginx serve)
- nginx.conf with gzip, caching, health endpoint

### flux/
- gitea-runner/: gitea-act-runner HelmRelease (org-scope, dind)
- monitoring/: kube-prometheus-stack + Gatus HelmReleases
  - Prometheus with pod annotation scraping
  - Grafana at grafana.leeworks.dev with persistence
  - Gatus status page at status.leeworks.dev, 90-day retention
- docs-site/: Deployment + Service + Ingress via raw chart
- api-company-source/: GitRepository + Kustomization reference manifests
- kustomization.yaml: root kustomize entry point (build validated)

### .gitea/workflows/build-docs.yaml
- Aggregates openapi.yaml from zip-enrichment, holidays, air-quality repos
- Builds Astro docs-site
- Pushes image to registry.leeworks.dev/leeworks-agents/docs-site
- Triggered on push to main, schedule daily 02:00 UTC, workflow_dispatch
This commit is contained in:
agent-company
2026-05-24 23:20:33 +00:00
parent 40631fee7c
commit a615b7ebfd
41 changed files with 2201 additions and 3 deletions
+31
View File
@@ -0,0 +1,31 @@
---
import Base from '../layouts/Base.astro';
const apiName = 'air-quality';
const titles: Record<string, string> = {
'zip-enrichment': 'ZIP Enrichment API',
'holidays': 'Holidays API',
'air-quality': 'Air Quality API',
};
const title = titles[apiName];
---
<Base title={title} description={`${title} — OpenAPI documentation`}>
<style>
#redoc-container { background: #fff; }
</style>
<div id="redoc-container"></div>
<script is:inline define:vars={{ specUrl: `/specs/${apiName}.yaml` }}>
// Load Redoc from CDN
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js';
script.onload = function () {
Redoc.init(specUrl, {
theme: {
colors: { primary: { main: '#667eea' } },
typography: { fontFamily: 'system-ui, sans-serif' },
},
}, document.getElementById('redoc-container'));
};
document.head.appendChild(script);
</script>
</Base>
@@ -0,0 +1,178 @@
---
title: "Air Quality API: Real-Time AQI Data for Any Location"
description: "Access real-time Air Quality Index (AQI) data, PM2.5, PM10, and health recommendations for any city worldwide using the leeworks.dev Air Quality API."
date: "2026-05-24"
author: "leeworks.dev"
tags: ["air-quality", "aqi", "api", "tutorial"]
---
import Base from '../../layouts/Base.astro';
<Base title="Air Quality API Guide" description="Access real-time AQI data for any location worldwide.">
<article style="max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.75;">
<script type="application/ld+json" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
"headline": "Air Quality API: Real-Time AQI Data for Any Location",
"datePublished": "2026-05-24",
"author": { "@type": "Organization", "name": "leeworks.dev" },
"publisher": { "@type": "Organization", "name": "leeworks.dev", "url": "https://docs.leeworks.dev" }
})} />
# Air Quality API: Real-Time AQI Data for Any Location
Whether you're building a fitness app, a travel planner, or a smart home dashboard, air quality data is increasingly essential. The leeworks.dev **Air Quality API** gives you real-time AQI readings, pollutant breakdowns, and health recommendations for any location in the world.
## What Is AQI and Why Does Your App Need It?
The **Air Quality Index (AQI)** is a standardized scale (0500) that communicates how clean or polluted the air is:
| AQI | Category | Health Implication |
|-----|----------|-------------------|
| 050 | Good | Air quality is satisfactory |
| 51100 | Moderate | Acceptable for most people |
| 101150 | Unhealthy for Sensitive Groups | At-risk groups may experience effects |
| 151200 | Unhealthy | Everyone may begin to experience health effects |
| 201300 | Very Unhealthy | Health alert: serious effects possible |
| 301500 | Hazardous | Emergency conditions |
**Use cases for an AQI data API:**
- **Fitness apps** — warn runners when outdoor exercise is unsafe
- **Travel apps** — show air quality forecasts for destination cities
- **Real estate platforms** — display neighborhood air quality scores
- **Smart home apps** — trigger air purifiers based on outdoor AQI
- **Health tracking apps** — correlate symptoms with air quality data
- **News and weather apps** — add AQI to daily weather cards
## Quick Start
```bash
# Get current AQI for a city
curl "https://aqi.leeworks.dev/v1/current?city=Los+Angeles&country=US" \
-H "X-RapidAPI-Key: YOUR_API_KEY"
```
Response:
```json
{
"location": {
"city": "Los Angeles",
"country": "US",
"latitude": 34.0522,
"longitude": -118.2437
},
"aqi": 87,
"category": "Moderate",
"pollutants": {
"pm25": 22.4,
"pm10": 35.1,
"o3": 41.2,
"no2": 18.5,
"so2": 2.1,
"co": 0.4
},
"health_recommendation": "Unusually sensitive people should consider reducing prolonged outdoor exertion.",
"updated_at": "2026-05-24T14:30:00Z"
}
```
## By Coordinates (Lat/Long)
```bash
curl "https://aqi.leeworks.dev/v1/current?lat=48.8566&lon=2.3522" \
-H "X-RapidAPI-Key: YOUR_API_KEY"
```
## Code Examples
### JavaScript
```javascript
async function getAirQuality(city, country = 'US') {
const response = await fetch(
`https://aqi.leeworks.dev/v1/current?city=${encodeURIComponent(city)}&country=${country}`,
{ headers: { 'X-RapidAPI-Key': process.env.RAPIDAPI_KEY } }
);
return response.json();
}
const data = await getAirQuality('Denver');
if (data.aqi > 100) {
console.warn(`Air quality in ${data.location.city} is ${data.category}. Consider staying indoors.`);
}
```
### Python
```python
import httpx
def get_aqi(lat: float, lon: float) -> dict:
resp = httpx.get(
"https://aqi.leeworks.dev/v1/current",
params={"lat": lat, "lon": lon},
headers={"X-RapidAPI-Key": "YOUR_KEY"},
)
resp.raise_for_status()
return resp.json()
# Example: check AQI before recommending outdoor run
aqi_data = get_aqi(37.7749, -122.4194) # San Francisco
if aqi_data["aqi"] <= 100:
print("Good to go for a run!")
else:
print(f"Air quality is {aqi_data['category']} — consider indoor exercise.")
```
### React Hook
```tsx
import { useState, useEffect } from 'react';
interface AQIData {
aqi: number;
category: string;
health_recommendation: string;
}
export function useAirQuality(city: string) {
const [data, setData] = useState<AQIData | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`/api/aqi?city=${encodeURIComponent(city)}`)
.then(r => r.json())
.then(setData)
.finally(() => setLoading(false));
}, [city]);
return { data, loading };
}
```
## Data Source
The leeworks.dev Air Quality API aggregates data from the **OpenAQ** public dataset — a non-profit platform that collects open air quality data from government agencies worldwide. Data is refreshed hourly.
## Pricing
| Plan | Requests/mo | Price |
|------|------------|-------|
| Free | 500 | $0 |
| Basic | 10,000 | $9/mo |
| Pro | 100,000 | $19/mo |
| Ultra | 1,000,000 | $49/mo |
**[Subscribe on RapidAPI →](https://rapidapi.com/leeworks/api/air-quality)**
## Conclusion
Air quality is no longer a niche data point — it's a critical health metric that millions of people check daily. The leeworks.dev **AQI data API** gives your app real-time air quality readings, pollutant breakdowns, and actionable health recommendations with a simple REST interface.
**[Start building for free →](https://rapidapi.com/leeworks/api/air-quality)**
</article>
</Base>
+29
View File
@@ -0,0 +1,29 @@
---
import Base from '../../layouts/Base.astro';
const posts = await Astro.glob('./*.mdx');
posts.sort((a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime());
---
<Base title="Blog" description="leeworks.dev developer blog">
<style>
.blog-hero { padding: 3rem 2rem 1rem; text-align: center; }
.blog-hero h1 { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; }
.blog-hero p { color: #a0aec0; }
.posts { max-width: 800px; margin: 2rem auto; padding: 0 2rem; }
.post-card { border-bottom: 1px solid #2d3748; padding: 2rem 0; }
.post-card h2 a { color: #90cdf4; text-decoration: none; font-size: 1.5rem; }
.meta { color: #718096; font-size: 0.875rem; margin: 0.5rem 0; }
.description { color: #a0aec0; }
</style>
<div class="blog-hero"><h1>Blog</h1><p>Tutorials and news from leeworks.dev</p></div>
<div class="posts">
{posts.map(post => (
<div class="post-card">
<h2><a href={post.url}>{post.frontmatter.title}</a></h2>
<div class="meta">{post.frontmatter.date}</div>
<p class="description">{post.frontmatter.description}</p>
</div>
))}
{posts.length === 0 && <p style="color: #718096">No posts yet.</p>}
</div>
</Base>
@@ -0,0 +1,161 @@
---
title: "Public Holidays API: The Free Holiday Calendar API for Any Country"
description: "Get public holidays for 100+ countries with a single API call. The leeworks.dev Holidays API is perfect for scheduling, calendar apps, and payroll systems."
date: "2026-05-24"
author: "leeworks.dev"
tags: ["holidays", "api", "tutorial"]
---
import Base from '../../layouts/Base.astro';
<Base title="Public Holidays API Guide" description="Get public holidays for 100+ countries with a single API call.">
<article style="max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.75;">
<script type="application/ld+json" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
"headline": "Public Holidays API: The Free Holiday Calendar API for Any Country",
"datePublished": "2026-05-24",
"author": { "@type": "Organization", "name": "leeworks.dev" },
"publisher": { "@type": "Organization", "name": "leeworks.dev", "url": "https://docs.leeworks.dev" }
})} />
# Public Holidays API: The Free Holiday Calendar API for Any Country
Building a scheduling app, payroll system, or booking platform? You need accurate **public holiday data** for every country you serve. The leeworks.dev **Holidays API** gives you that data in milliseconds.
## Why You Need a Holiday Calendar API
Manually maintaining a list of public holidays is a losing battle. Holidays change year to year, differ by country and region, and missing one can mean:
- **Wrong delivery estimates** on e-commerce sites
- **Incorrect payroll calculations** (overtime on holidays)
- **Broken calendar apps** that schedule meetings on national holidays
- **Failed SLA commitments** that assumed business days
A reliable **holiday API** solves this once.
## What the leeworks.dev Holidays API Provides
- Public holidays for **100+ countries**
- Data updated from Nager.Date's curated public dataset
- Filter by **country code** (ISO 3166-1 alpha-2), **year**, and **type**
- Response includes holiday name (localized), date, and type (`public`, `optional`, `observance`)
- Sub-100ms response time, SQLite-backed
## Quick Start
```bash
# Get all US public holidays for 2026
curl "https://holidays.leeworks.dev/v1/holidays?country=US&year=2026" \
-H "X-RapidAPI-Key: YOUR_API_KEY"
```
Response:
```json
{
"country": "US",
"year": 2026,
"holidays": [
{
"date": "2026-01-01",
"name": "New Year's Day",
"type": "public"
},
{
"date": "2026-07-04",
"name": "Independence Day",
"type": "public"
}
]
}
```
## Common Use Cases
### 1. Skip Holidays in Business Day Calculations
```python
from datetime import date, timedelta
import httpx
def next_business_day(start: date, country: str = "US") -> date:
resp = httpx.get(
"https://holidays.leeworks.dev/v1/holidays",
params={"country": country, "year": start.year},
headers={"X-RapidAPI-Key": "YOUR_KEY"},
)
holidays = {h["date"] for h in resp.json()["holidays"]}
current = start + timedelta(days=1)
while current.weekday() >= 5 or current.isoformat() in holidays:
current += timedelta(days=1)
return current
```
### 2. Display Holiday Badges in a Calendar
```javascript
async function getHolidayMap(countryCode, year) {
const res = await fetch(
`https://holidays.leeworks.dev/v1/holidays?country=${countryCode}&year=${year}`,
{ headers: { 'X-RapidAPI-Key': process.env.RAPIDAPI_KEY } }
);
const { holidays } = await res.json();
// Return a Map of ISO date string → holiday name
return new Map(holidays.map(h => [h.date, h.name]));
}
// Usage in a calendar component
const holidayMap = await getHolidayMap('GB', 2026);
const isHoliday = holidayMap.has('2026-12-25'); // true: Christmas Day
```
### 3. Check If Today Is a Holiday
```typescript
async function isTodayHoliday(country = 'US'): Promise<string | null> {
const today = new Date().toISOString().split('T')[0];
const year = new Date().getFullYear();
const res = await fetch(
`https://holidays.leeworks.dev/v1/is-holiday?country=${country}&date=${today}`,
{ headers: { 'X-RapidAPI-Key': process.env.RAPIDAPI_KEY! } }
);
const data = await res.json();
return data.isHoliday ? data.name : null;
}
```
## Supported Countries (Sample)
| Code | Country | Code | Country |
|------|---------|------|---------|
| US | United States | GB | United Kingdom |
| CA | Canada | DE | Germany |
| FR | France | JP | Japan |
| AU | Australia | BR | Brazil |
| IN | India | MX | Mexico |
...and 90+ more. Use `GET /v1/countries` to see the full list.
## Pricing
| Plan | Requests/mo | Price |
|------|------------|-------|
| Free | 500 | $0 |
| Basic | 10,000 | $9/mo |
| Pro | 100,000 | $19/mo |
| Ultra | 1,000,000 | $49/mo |
**[Subscribe on RapidAPI →](https://rapidapi.com/leeworks/api/holidays)**
## Conclusion
Stop hardcoding holiday lists or scraping Wikipedia. The leeworks.dev **public holidays API** gives you accurate, up-to-date holiday data for every country you need — with a simple REST interface and affordable pricing.
**[Get started for free →](https://rapidapi.com/leeworks/api/holidays)**
</article>
</Base>
@@ -0,0 +1,158 @@
---
title: "ZIP Code Enrichment API: Add Location Intelligence to Your App in Minutes"
description: "Learn how to use the leeworks.dev ZIP Code Enrichment API to add city, state, timezone, and demographic data to any postal code lookup."
date: "2026-05-24"
author: "leeworks.dev"
tags: ["zip-enrichment", "api", "tutorial"]
---
import Base from '../../layouts/Base.astro';
<Base title="ZIP Code Enrichment API Guide" description="Learn how to use the leeworks.dev ZIP Code Enrichment API to add city, state, timezone, and demographic data to any postal code lookup.">
<article style="max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.75;">
<script type="application/ld+json" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
"headline": "ZIP Code Enrichment API: Add Location Intelligence to Your App in Minutes",
"datePublished": "2026-05-24",
"author": { "@type": "Organization", "name": "leeworks.dev" },
"publisher": { "@type": "Organization", "name": "leeworks.dev", "url": "https://docs.leeworks.dev" }
})} />
# ZIP Code Enrichment API: Add Location Intelligence to Your App in Minutes
Every time a user types their ZIP code, there's a wealth of data waiting to be unlocked — city name, state, county, timezone, latitude, longitude, and more. The **leeworks.dev ZIP Code Enrichment API** makes it trivially easy to retrieve all of that in a single API call.
## What Is a ZIP Code Enrichment API?
A **postal code demographics API** (or ZIP enrichment API) takes a 5-digit US ZIP code as input and returns structured data about that location. This is useful for:
- **E-commerce** — display the user's city/state after they type a ZIP, skip the state dropdown
- **Shipping calculators** — determine timezone and region for delivery estimates
- **Analytics dashboards** — group customers by region, state, or county
- **Lead scoring** — enrich CRM contacts with location data automatically
- **Form UX** — auto-fill city/state fields for a smoother checkout experience
## Why Build on leeworks.dev?
Unlike scraping Google Maps or paying for expensive enterprise solutions, the leeworks.dev ZIP Enrichment API:
- Returns **sub-50ms responses** (SQLite-backed, no external dependencies)
- Provides **100% US ZIP code coverage** using the free USPS/Census dataset
- Is available on **RapidAPI** with a generous free tier
- Has a **simple, well-documented REST API** following the OpenAPI 3.1 standard
## Quick Start
### 1. Get Your API Key
Sign up on [RapidAPI](https://rapidapi.com/leeworks/api/zip-enrichment) and subscribe to a plan. The Free tier gives you 500 requests/month.
### 2. Make Your First Call
```bash
curl -X GET "https://zip.leeworks.dev/v1/lookup?zip=90210" \
-H "X-RapidAPI-Key: YOUR_API_KEY" \
-H "X-RapidAPI-Host: zip.leeworks.dev"
```
### 3. Parse the Response
```json
{
"zip": "90210",
"city": "Beverly Hills",
"state": "CA",
"state_full": "California",
"county": "Los Angeles",
"timezone": "America/Los_Angeles",
"latitude": 34.0901,
"longitude": -118.4065,
"population": 20124
}
```
## Code Examples
### JavaScript / Node.js
```javascript
const response = await fetch('https://zip.leeworks.dev/v1/lookup?zip=10001', {
headers: {
'X-RapidAPI-Key': process.env.RAPIDAPI_KEY,
'X-RapidAPI-Host': 'zip.leeworks.dev',
},
});
const data = await response.json();
console.log(`${data.city}, ${data.state} (${data.timezone})`);
// → "New York, NY (America/New_York)"
```
### Python
```python
import httpx
resp = httpx.get(
"https://zip.leeworks.dev/v1/lookup",
params={"zip": "60601"},
headers={
"X-RapidAPI-Key": "YOUR_API_KEY",
"X-RapidAPI-Host": "zip.leeworks.dev",
},
)
data = resp.json()
print(f"{data['city']}, {data['state']}")
# → "Chicago, IL"
```
## Pricing
| Plan | Requests/mo | Price | Best for |
|------|------------|-------|---------|
| Free | 500 | $0 | Prototyping |
| Basic | 10,000 | $9/mo | Small apps |
| Pro | 100,000 | $19/mo | Growing products |
| Ultra | 1,000,000 | $49/mo | High volume |
**[Subscribe on RapidAPI →](https://rapidapi.com/leeworks/api/zip-enrichment)**
## Use Case: Auto-fill City/State on Checkout
Here's a complete React component that auto-fills city and state when a user enters their ZIP:
```tsx
import { useState } from 'react';
export function ZipField() {
const [zip, setZip] = useState('');
const [location, setLocation] = useState<{ city: string; state: string } | null>(null);
const handleZipChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value.replace(/\D/g, '').slice(0, 5);
setZip(value);
if (value.length === 5) {
const res = await fetch(`/api/zip-lookup?zip=${value}`);
if (res.ok) setLocation(await res.json());
}
};
return (
<div>
<input value={zip} onChange={handleZipChange} placeholder="ZIP Code" maxLength={5} />
{location && <p>📍 {location.city}, {location.state}</p>}
</div>
);
}
```
## Conclusion
The leeworks.dev **ZIP code enrichment API** is the fastest way to add location intelligence to any application. With a simple GET request, you get city, state, county, timezone, and coordinates — no geocoding, no rate-limit headaches.
**[Get started for free →](https://rapidapi.com/leeworks/api/zip-enrichment)**
</article>
</Base>
+31
View File
@@ -0,0 +1,31 @@
---
import Base from '../layouts/Base.astro';
const apiName = 'holidays';
const titles: Record<string, string> = {
'zip-enrichment': 'ZIP Enrichment API',
'holidays': 'Holidays API',
'air-quality': 'Air Quality API',
};
const title = titles[apiName];
---
<Base title={title} description={`${title} — OpenAPI documentation`}>
<style>
#redoc-container { background: #fff; }
</style>
<div id="redoc-container"></div>
<script is:inline define:vars={{ specUrl: `/specs/${apiName}.yaml` }}>
// Load Redoc from CDN
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js';
script.onload = function () {
Redoc.init(specUrl, {
theme: {
colors: { primary: { main: '#667eea' } },
typography: { fontFamily: 'system-ui, sans-serif' },
},
}, document.getElementById('redoc-container'));
};
document.head.appendChild(script);
</script>
</Base>
+56
View File
@@ -0,0 +1,56 @@
---
import Base from '../layouts/Base.astro';
---
<Base title="Home" description="leeworks.dev — production-ready data APIs: ZIP Enrichment, Holidays, Air Quality">
<style>
.hero { padding: 5rem 2rem 3rem; text-align: center; }
.hero h1 { font-size: 3rem; font-weight: 800; background: linear-gradient(135deg, #90cdf4, #667eea); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem; }
.hero p { font-size: 1.25rem; color: #a0aec0; max-width: 600px; margin: 0 auto 2rem; }
.cta { display: inline-block; background: #667eea; color: #fff; padding: 0.75rem 2rem; border-radius: 8px; text-decoration: none; font-weight: 600; }
.apis { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; padding: 2rem; max-width: 1100px; margin: 0 auto; }
.api-card { background: #1a1d27; border: 1px solid #2d3748; border-radius: 12px; padding: 1.5rem; }
.api-card h2 { color: #90cdf4; margin-bottom: 0.5rem; }
.api-card p { color: #a0aec0; margin-bottom: 1rem; font-size: 0.95rem; }
.badge { display: inline-block; font-size: 0.75rem; padding: 0.2rem 0.6rem; border-radius: 4px; margin-bottom: 0.75rem; }
.badge.wip { background: #744210; color: #fbd38d; }
.badge.live { background: #1a4731; color: #9ae6b4; }
.links a { color: #90cdf4; text-decoration: none; margin-right: 1rem; }
.links a:hover { text-decoration: underline; }
</style>
<div class="hero">
<h1>Simple. Reliable. APIs.</h1>
<p>Production-ready data APIs for ZIP enrichment, public holidays, and air quality. Available on RapidAPI.</p>
<a href="https://rapidapi.com/leeworks" class="cta" target="_blank" rel="noopener">Get API Key on RapidAPI</a>
</div>
<div class="apis">
<div class="api-card">
<span class="badge wip">In Development</span>
<h2>ZIP Enrichment API</h2>
<p>Enrich US ZIP codes with city, state, county, timezone, lat/long, and population data.</p>
<div class="links">
<a href="/zip-enrichment">Docs</a>
<a href="https://rapidapi.com/leeworks/api/zip-enrichment" target="_blank" rel="noopener">RapidAPI</a>
</div>
</div>
<div class="api-card">
<span class="badge wip">In Development</span>
<h2>Holidays API</h2>
<p>Public holidays for 100+ countries, filterable by country, year, and type.</p>
<div class="links">
<a href="/holidays">Docs</a>
<a href="https://rapidapi.com/leeworks/api/holidays" target="_blank" rel="noopener">RapidAPI</a>
</div>
</div>
<div class="api-card">
<span class="badge wip">In Development</span>
<h2>Air Quality API</h2>
<p>Real-time and historical AQI data worldwide including PM2.5, PM10, and health recommendations.</p>
<div class="links">
<a href="/air-quality">Docs</a>
<a href="https://rapidapi.com/leeworks/api/air-quality" target="_blank" rel="noopener">RapidAPI</a>
</div>
</div>
</div>
</Base>
+31
View File
@@ -0,0 +1,31 @@
---
import Base from '../layouts/Base.astro';
const apiName = 'zip-enrichment';
const titles: Record<string, string> = {
'zip-enrichment': 'ZIP Enrichment API',
'holidays': 'Holidays API',
'air-quality': 'Air Quality API',
};
const title = titles[apiName];
---
<Base title={title} description={`${title} — OpenAPI documentation`}>
<style>
#redoc-container { background: #fff; }
</style>
<div id="redoc-container"></div>
<script is:inline define:vars={{ specUrl: `/specs/${apiName}.yaml` }}>
// Load Redoc from CDN
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js';
script.onload = function () {
Redoc.init(specUrl, {
theme: {
colors: { primary: { main: '#667eea' } },
typography: { fontFamily: 'system-ui, sans-serif' },
},
}, document.getElementById('redoc-container'));
};
document.head.appendChild(script);
</script>
</Base>