beachdayapi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- beachdayapi-0.1.0/PKG-INFO +122 -0
- beachdayapi-0.1.0/README.md +97 -0
- beachdayapi-0.1.0/beachdayapi/__init__.py +29 -0
- beachdayapi-0.1.0/beachdayapi/client.py +157 -0
- beachdayapi-0.1.0/beachdayapi/exceptions.py +28 -0
- beachdayapi-0.1.0/beachdayapi.egg-info/PKG-INFO +122 -0
- beachdayapi-0.1.0/beachdayapi.egg-info/SOURCES.txt +9 -0
- beachdayapi-0.1.0/beachdayapi.egg-info/dependency_links.txt +1 -0
- beachdayapi-0.1.0/beachdayapi.egg-info/top_level.txt +1 -0
- beachdayapi-0.1.0/pyproject.toml +36 -0
- beachdayapi-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: beachdayapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Beach Day API — real-time beach and surf conditions
|
|
5
|
+
Author-email: Beach Day API <hello@beachdayapi.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://beachdayapi.com
|
|
8
|
+
Project-URL: Documentation, https://beachdayapi.com/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/rv888/beachdayapi
|
|
10
|
+
Project-URL: Issues, https://github.com/rv888/beachdayapi/issues
|
|
11
|
+
Keywords: beach,surf,water-quality,weather,api
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Beach Day API — Python Client
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
29
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
Python client for the [Beach Day API](https://beachdayapi.com) — water quality, weather, tides, ocean conditions, beach rules, amenities, and composite scoring in a single call. Covers 1,900+ beaches across the US and Australia.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install beachdayapi
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from beachdayapi import BeachDayAPI
|
|
42
|
+
|
|
43
|
+
client = BeachDayAPI("bda_your_api_key")
|
|
44
|
+
|
|
45
|
+
# Search beaches in California
|
|
46
|
+
beaches = client.beaches.list(state="CA")
|
|
47
|
+
for b in beaches["data"]:
|
|
48
|
+
print(b["name"], b["state"])
|
|
49
|
+
|
|
50
|
+
# Get full detail for a beach
|
|
51
|
+
beach = client.beaches.get(372)
|
|
52
|
+
print(beach["data"]["name"], beach["data"]["beach_day_score"])
|
|
53
|
+
|
|
54
|
+
# Get current conditions
|
|
55
|
+
conditions = client.beaches.conditions(372)
|
|
56
|
+
print(conditions["data"]["water_quality_grade"])
|
|
57
|
+
|
|
58
|
+
# Get top-scored beaches
|
|
59
|
+
scored = client.beaches.scored(min_score=70, limit=10)
|
|
60
|
+
for b in scored["data"]:
|
|
61
|
+
print(f"{b['name']}: {b['beach_day_score']}")
|
|
62
|
+
|
|
63
|
+
# Health check (no API key needed)
|
|
64
|
+
health = client.health()
|
|
65
|
+
print(health)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API Key
|
|
69
|
+
|
|
70
|
+
Sign up at [beachdayapi.com](https://beachdayapi.com) to get your free API key (50 free credits, no credit card). Your key starts with `bda_`.
|
|
71
|
+
|
|
72
|
+
You can also set the `BEACHDAY_API_KEY` environment variable:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import os
|
|
76
|
+
from beachdayapi import BeachDayAPI
|
|
77
|
+
|
|
78
|
+
client = BeachDayAPI(os.environ["BEACHDAY_API_KEY"])
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Endpoints
|
|
82
|
+
|
|
83
|
+
| Method | Endpoint | Cost | Description |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| `client.health()` | `GET /v1/health` | Free | API health check |
|
|
86
|
+
| `client.beaches.list()` | `GET /v1/beaches` | 1 credit | Search beaches |
|
|
87
|
+
| `client.beaches.get(id)` | `GET /v1/beaches/{id}` | 5 credits | Beach detail |
|
|
88
|
+
| `client.beaches.conditions(id)` | `GET /v1/beaches/{id}/conditions` | 3 credits | Current conditions |
|
|
89
|
+
| `client.beaches.scored()` | `GET /v1/beaches/scored` | 10 credits | Scored beaches |
|
|
90
|
+
|
|
91
|
+
## Error Handling
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from beachdayapi import (
|
|
95
|
+
BeachDayAPI,
|
|
96
|
+
AuthenticationError,
|
|
97
|
+
InsufficientCreditsError,
|
|
98
|
+
NotFoundError,
|
|
99
|
+
RateLimitError,
|
|
100
|
+
ServerError,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
client = BeachDayAPI("bda_invalid_key")
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
client.beaches.list(state="CA")
|
|
107
|
+
except AuthenticationError:
|
|
108
|
+
print("Check your API key")
|
|
109
|
+
except InsufficientCreditsError:
|
|
110
|
+
print("Buy more credits at beachdayapi.com/credits/pricing/")
|
|
111
|
+
except RateLimitError:
|
|
112
|
+
print("Slow down")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- Python 3.9+
|
|
118
|
+
- Zero dependencies (stdlib only)
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT — see the main [Beach Day API repository](https://github.com/rv888/beachdayapi).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Beach Day API — Python Client
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
4
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Python client for the [Beach Day API](https://beachdayapi.com) — water quality, weather, tides, ocean conditions, beach rules, amenities, and composite scoring in a single call. Covers 1,900+ beaches across the US and Australia.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install beachdayapi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from beachdayapi import BeachDayAPI
|
|
17
|
+
|
|
18
|
+
client = BeachDayAPI("bda_your_api_key")
|
|
19
|
+
|
|
20
|
+
# Search beaches in California
|
|
21
|
+
beaches = client.beaches.list(state="CA")
|
|
22
|
+
for b in beaches["data"]:
|
|
23
|
+
print(b["name"], b["state"])
|
|
24
|
+
|
|
25
|
+
# Get full detail for a beach
|
|
26
|
+
beach = client.beaches.get(372)
|
|
27
|
+
print(beach["data"]["name"], beach["data"]["beach_day_score"])
|
|
28
|
+
|
|
29
|
+
# Get current conditions
|
|
30
|
+
conditions = client.beaches.conditions(372)
|
|
31
|
+
print(conditions["data"]["water_quality_grade"])
|
|
32
|
+
|
|
33
|
+
# Get top-scored beaches
|
|
34
|
+
scored = client.beaches.scored(min_score=70, limit=10)
|
|
35
|
+
for b in scored["data"]:
|
|
36
|
+
print(f"{b['name']}: {b['beach_day_score']}")
|
|
37
|
+
|
|
38
|
+
# Health check (no API key needed)
|
|
39
|
+
health = client.health()
|
|
40
|
+
print(health)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API Key
|
|
44
|
+
|
|
45
|
+
Sign up at [beachdayapi.com](https://beachdayapi.com) to get your free API key (50 free credits, no credit card). Your key starts with `bda_`.
|
|
46
|
+
|
|
47
|
+
You can also set the `BEACHDAY_API_KEY` environment variable:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import os
|
|
51
|
+
from beachdayapi import BeachDayAPI
|
|
52
|
+
|
|
53
|
+
client = BeachDayAPI(os.environ["BEACHDAY_API_KEY"])
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Endpoints
|
|
57
|
+
|
|
58
|
+
| Method | Endpoint | Cost | Description |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `client.health()` | `GET /v1/health` | Free | API health check |
|
|
61
|
+
| `client.beaches.list()` | `GET /v1/beaches` | 1 credit | Search beaches |
|
|
62
|
+
| `client.beaches.get(id)` | `GET /v1/beaches/{id}` | 5 credits | Beach detail |
|
|
63
|
+
| `client.beaches.conditions(id)` | `GET /v1/beaches/{id}/conditions` | 3 credits | Current conditions |
|
|
64
|
+
| `client.beaches.scored()` | `GET /v1/beaches/scored` | 10 credits | Scored beaches |
|
|
65
|
+
|
|
66
|
+
## Error Handling
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from beachdayapi import (
|
|
70
|
+
BeachDayAPI,
|
|
71
|
+
AuthenticationError,
|
|
72
|
+
InsufficientCreditsError,
|
|
73
|
+
NotFoundError,
|
|
74
|
+
RateLimitError,
|
|
75
|
+
ServerError,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
client = BeachDayAPI("bda_invalid_key")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
client.beaches.list(state="CA")
|
|
82
|
+
except AuthenticationError:
|
|
83
|
+
print("Check your API key")
|
|
84
|
+
except InsufficientCreditsError:
|
|
85
|
+
print("Buy more credits at beachdayapi.com/credits/pricing/")
|
|
86
|
+
except RateLimitError:
|
|
87
|
+
print("Slow down")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Requirements
|
|
91
|
+
|
|
92
|
+
- Python 3.9+
|
|
93
|
+
- Zero dependencies (stdlib only)
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT — see the main [Beach Day API repository](https://github.com/rv888/beachdayapi).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Beach Day API Python Client
|
|
2
|
+
|
|
3
|
+
A lightweight Python client for the Beach Day API.
|
|
4
|
+
|
|
5
|
+
pip install beachdayapi
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from beachdayapi import BeachDayAPI
|
|
9
|
+
|
|
10
|
+
client = BeachDayAPI("bda_your_api_key")
|
|
11
|
+
|
|
12
|
+
# Search beaches
|
|
13
|
+
beaches = client.beaches.list(state="CA")
|
|
14
|
+
|
|
15
|
+
# Get beach detail
|
|
16
|
+
beach = client.beaches.get(372)
|
|
17
|
+
|
|
18
|
+
# Get scored beaches
|
|
19
|
+
scored = client.beaches.scored(min_score=70)
|
|
20
|
+
|
|
21
|
+
# Health check (no auth)
|
|
22
|
+
health = client.health()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from .client import BeachDayAPI
|
|
26
|
+
from .exceptions import BeachDayAPIError, AuthenticationError, InsufficientCreditsError
|
|
27
|
+
|
|
28
|
+
__all__ = ["BeachDayAPI", "BeachDayAPIError", "AuthenticationError", "InsufficientCreditsError"]
|
|
29
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import urllib.request
|
|
2
|
+
import urllib.error
|
|
3
|
+
import urllib.parse
|
|
4
|
+
import json
|
|
5
|
+
from typing import Optional, Dict, Any, List
|
|
6
|
+
from .exceptions import (
|
|
7
|
+
AuthenticationError,
|
|
8
|
+
InsufficientCreditsError,
|
|
9
|
+
NotFoundError,
|
|
10
|
+
RateLimitError,
|
|
11
|
+
ServerError,
|
|
12
|
+
BeachDayAPIError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BeachDayAPI:
|
|
17
|
+
"""Client for the Beach Day API.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
api_key: Your Beach Day API key (starts with 'bda_').
|
|
21
|
+
base_url: Override the API base URL. Defaults to production.
|
|
22
|
+
timeout: Request timeout in seconds. Default 30.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
BASE_URL = "https://beachdayapi.com/v1"
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
api_key: Optional[str] = None,
|
|
30
|
+
base_url: Optional[str] = None,
|
|
31
|
+
timeout: int = 30,
|
|
32
|
+
):
|
|
33
|
+
self.api_key = api_key
|
|
34
|
+
self.base_url = base_url or self.BASE_URL
|
|
35
|
+
self.timeout = timeout
|
|
36
|
+
self.beaches = BeachEndpoints(self)
|
|
37
|
+
self.health = lambda: self._get("/health", auth_required=False)
|
|
38
|
+
|
|
39
|
+
def _auth_headers(self) -> Dict[str, str]:
|
|
40
|
+
return {"Authorization": f"Bearer {self.api_key}"}
|
|
41
|
+
|
|
42
|
+
def _request(
|
|
43
|
+
self,
|
|
44
|
+
method: str,
|
|
45
|
+
path: str,
|
|
46
|
+
params: Optional[Dict[str, Any]] = None,
|
|
47
|
+
auth_required: bool = True,
|
|
48
|
+
) -> Dict[str, Any]:
|
|
49
|
+
url = f"{self.base_url}{path}"
|
|
50
|
+
headers = {"Accept": "application/json", "User-Agent": "beachdayapi-python/0.1.0"}
|
|
51
|
+
if auth_required:
|
|
52
|
+
if not self.api_key:
|
|
53
|
+
raise AuthenticationError(
|
|
54
|
+
"API key required. Pass api_key='bda_...' to BeachDayAPI(), "
|
|
55
|
+
"or set BEACHDAY_API_KEY environment variable."
|
|
56
|
+
)
|
|
57
|
+
headers.update(self._auth_headers())
|
|
58
|
+
|
|
59
|
+
if params:
|
|
60
|
+
filtered = {k: v for k, v in params.items() if v is not None}
|
|
61
|
+
if filtered:
|
|
62
|
+
url = f"{url}?{urllib.parse.urlencode(filtered)}"
|
|
63
|
+
|
|
64
|
+
req = urllib.request.Request(url, method=method, headers=headers)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
68
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
69
|
+
except urllib.error.HTTPError as e:
|
|
70
|
+
body = {}
|
|
71
|
+
try:
|
|
72
|
+
body = json.loads(e.read().decode("utf-8"))
|
|
73
|
+
except Exception:
|
|
74
|
+
pass
|
|
75
|
+
self._raise_error(e.code, body)
|
|
76
|
+
return {} # unreachable, satisfies type checker
|
|
77
|
+
except urllib.error.URLError as e:
|
|
78
|
+
raise BeachDayAPIError(f"Connection error: {e.reason}") from e
|
|
79
|
+
|
|
80
|
+
def _get(
|
|
81
|
+
self, path: str, params=None, auth_required=True
|
|
82
|
+
) -> Dict[str, Any]:
|
|
83
|
+
return self._request("GET", path, params, auth_required)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _raise_error(status: int, body: dict):
|
|
87
|
+
detail = body.get("detail") or body.get("message", "")
|
|
88
|
+
if status == 401:
|
|
89
|
+
raise AuthenticationError(detail or "Invalid or missing API key.")
|
|
90
|
+
if status == 402:
|
|
91
|
+
required = body.get("required", "?")
|
|
92
|
+
balance = body.get("balance", "?")
|
|
93
|
+
msg = f"Insufficient credits. Need {required}, have {balance}."
|
|
94
|
+
raise InsufficientCreditsError(msg)
|
|
95
|
+
if status == 404:
|
|
96
|
+
raise NotFoundError(detail or "Resource not found.")
|
|
97
|
+
if status == 429:
|
|
98
|
+
raise RateLimitError(detail or "Too many requests.")
|
|
99
|
+
if 500 <= status < 600:
|
|
100
|
+
raise ServerError(detail or f"Server error (HTTP {status}).")
|
|
101
|
+
raise BeachDayAPIError(f"HTTP {status}: {detail or 'Unknown error'}")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class BeachEndpoints:
|
|
105
|
+
"""Access beach-related endpoints."""
|
|
106
|
+
|
|
107
|
+
def __init__(self, client: BeachDayAPI):
|
|
108
|
+
self._client = client
|
|
109
|
+
|
|
110
|
+
def list(
|
|
111
|
+
self,
|
|
112
|
+
state: Optional[str] = None,
|
|
113
|
+
search: Optional[str] = None,
|
|
114
|
+
limit: Optional[int] = None,
|
|
115
|
+
offset: Optional[int] = None,
|
|
116
|
+
) -> Dict[str, Any]:
|
|
117
|
+
"""List beaches with optional filters.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
state: Two-letter US state code or 'AU-NSW'/'AU-VIC'.
|
|
121
|
+
search: Search term for beach name.
|
|
122
|
+
limit: Max results per page.
|
|
123
|
+
offset: Pagination offset.
|
|
124
|
+
"""
|
|
125
|
+
return self._client._get("/beaches", {
|
|
126
|
+
"state": state,
|
|
127
|
+
"search": search,
|
|
128
|
+
"limit": limit,
|
|
129
|
+
"offset": offset,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
def get(self, beach_id: int) -> Dict[str, Any]:
|
|
133
|
+
"""Get full detail for a single beach."""
|
|
134
|
+
return self._client._get(f"/beaches/{beach_id}")
|
|
135
|
+
|
|
136
|
+
def conditions(self, beach_id: int) -> Dict[str, Any]:
|
|
137
|
+
"""Get current conditions for a beach."""
|
|
138
|
+
return self._client._get(f"/beaches/{beach_id}/conditions")
|
|
139
|
+
|
|
140
|
+
def scored(
|
|
141
|
+
self,
|
|
142
|
+
state: Optional[str] = None,
|
|
143
|
+
min_score: Optional[int] = None,
|
|
144
|
+
limit: Optional[int] = None,
|
|
145
|
+
) -> Dict[str, Any]:
|
|
146
|
+
"""Get beaches with composite Beach Day Scores.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
state: Filter by state code.
|
|
150
|
+
min_score: Minimum score threshold (0-100).
|
|
151
|
+
limit: Max results.
|
|
152
|
+
"""
|
|
153
|
+
return self._client._get("/beaches/scored", {
|
|
154
|
+
"state": state,
|
|
155
|
+
"min_score": min_score,
|
|
156
|
+
"limit": limit,
|
|
157
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class BeachDayAPIError(Exception):
|
|
2
|
+
"""Base exception for Beach Day API errors."""
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AuthenticationError(BeachDayAPIError):
|
|
7
|
+
"""Invalid or missing API key (HTTP 401)."""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InsufficientCreditsError(BeachDayAPIError):
|
|
12
|
+
"""Not enough credits for the request (HTTP 402)."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NotFoundError(BeachDayAPIError):
|
|
17
|
+
"""Resource not found (HTTP 404)."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class RateLimitError(BeachDayAPIError):
|
|
22
|
+
"""Rate limit exceeded (HTTP 429)."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ServerError(BeachDayAPIError):
|
|
27
|
+
"""Server-side error (HTTP 5xx)."""
|
|
28
|
+
pass
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: beachdayapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Beach Day API — real-time beach and surf conditions
|
|
5
|
+
Author-email: Beach Day API <hello@beachdayapi.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://beachdayapi.com
|
|
8
|
+
Project-URL: Documentation, https://beachdayapi.com/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/rv888/beachdayapi
|
|
10
|
+
Project-URL: Issues, https://github.com/rv888/beachdayapi/issues
|
|
11
|
+
Keywords: beach,surf,water-quality,weather,api
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Beach Day API — Python Client
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
29
|
+
[](https://pypi.org/project/beachdayapi/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
Python client for the [Beach Day API](https://beachdayapi.com) — water quality, weather, tides, ocean conditions, beach rules, amenities, and composite scoring in a single call. Covers 1,900+ beaches across the US and Australia.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install beachdayapi
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from beachdayapi import BeachDayAPI
|
|
42
|
+
|
|
43
|
+
client = BeachDayAPI("bda_your_api_key")
|
|
44
|
+
|
|
45
|
+
# Search beaches in California
|
|
46
|
+
beaches = client.beaches.list(state="CA")
|
|
47
|
+
for b in beaches["data"]:
|
|
48
|
+
print(b["name"], b["state"])
|
|
49
|
+
|
|
50
|
+
# Get full detail for a beach
|
|
51
|
+
beach = client.beaches.get(372)
|
|
52
|
+
print(beach["data"]["name"], beach["data"]["beach_day_score"])
|
|
53
|
+
|
|
54
|
+
# Get current conditions
|
|
55
|
+
conditions = client.beaches.conditions(372)
|
|
56
|
+
print(conditions["data"]["water_quality_grade"])
|
|
57
|
+
|
|
58
|
+
# Get top-scored beaches
|
|
59
|
+
scored = client.beaches.scored(min_score=70, limit=10)
|
|
60
|
+
for b in scored["data"]:
|
|
61
|
+
print(f"{b['name']}: {b['beach_day_score']}")
|
|
62
|
+
|
|
63
|
+
# Health check (no API key needed)
|
|
64
|
+
health = client.health()
|
|
65
|
+
print(health)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API Key
|
|
69
|
+
|
|
70
|
+
Sign up at [beachdayapi.com](https://beachdayapi.com) to get your free API key (50 free credits, no credit card). Your key starts with `bda_`.
|
|
71
|
+
|
|
72
|
+
You can also set the `BEACHDAY_API_KEY` environment variable:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import os
|
|
76
|
+
from beachdayapi import BeachDayAPI
|
|
77
|
+
|
|
78
|
+
client = BeachDayAPI(os.environ["BEACHDAY_API_KEY"])
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Endpoints
|
|
82
|
+
|
|
83
|
+
| Method | Endpoint | Cost | Description |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| `client.health()` | `GET /v1/health` | Free | API health check |
|
|
86
|
+
| `client.beaches.list()` | `GET /v1/beaches` | 1 credit | Search beaches |
|
|
87
|
+
| `client.beaches.get(id)` | `GET /v1/beaches/{id}` | 5 credits | Beach detail |
|
|
88
|
+
| `client.beaches.conditions(id)` | `GET /v1/beaches/{id}/conditions` | 3 credits | Current conditions |
|
|
89
|
+
| `client.beaches.scored()` | `GET /v1/beaches/scored` | 10 credits | Scored beaches |
|
|
90
|
+
|
|
91
|
+
## Error Handling
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from beachdayapi import (
|
|
95
|
+
BeachDayAPI,
|
|
96
|
+
AuthenticationError,
|
|
97
|
+
InsufficientCreditsError,
|
|
98
|
+
NotFoundError,
|
|
99
|
+
RateLimitError,
|
|
100
|
+
ServerError,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
client = BeachDayAPI("bda_invalid_key")
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
client.beaches.list(state="CA")
|
|
107
|
+
except AuthenticationError:
|
|
108
|
+
print("Check your API key")
|
|
109
|
+
except InsufficientCreditsError:
|
|
110
|
+
print("Buy more credits at beachdayapi.com/credits/pricing/")
|
|
111
|
+
except RateLimitError:
|
|
112
|
+
print("Slow down")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- Python 3.9+
|
|
118
|
+
- Zero dependencies (stdlib only)
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT — see the main [Beach Day API repository](https://github.com/rv888/beachdayapi).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
beachdayapi
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "beachdayapi"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for the Beach Day API — real-time beach and surf conditions"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
authors = [{name = "Beach Day API", email = "hello@beachdayapi.com"}]
|
|
12
|
+
keywords = ["beach", "surf", "water-quality", "weather", "api"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Atmospheric Science",
|
|
24
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
25
|
+
]
|
|
26
|
+
requires-python = ">=3.9"
|
|
27
|
+
dependencies = []
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://beachdayapi.com"
|
|
31
|
+
Documentation = "https://beachdayapi.com/docs"
|
|
32
|
+
Repository = "https://github.com/rv888/beachdayapi"
|
|
33
|
+
Issues = "https://github.com/rv888/beachdayapi/issues"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools]
|
|
36
|
+
packages = ["beachdayapi"]
|