Skip to content

Commit abd154d

Browse files
authored
Add @neaps/api HTTP JSON API package (#192)
1 parent 84732a2 commit abd154d

13 files changed

Lines changed: 1441 additions & 2 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ A tide prediction engine written in TypeScript.
99
>
1010
> Do not use calculations from this project for navigation, or depend on them in any situation where inaccuracies could result in harm to a person or property. Tide predictions are only as good as the harmonics data available, and these can be inconsistent and vary widely based on the accuracy of the source data and local conditions. The tide predictions do not factor events such as storm surge, wind waves, uplift, tsunamis, or sadly, climate change. 😢
1111
12+
## Packages
13+
14+
This monorepo contains:
15+
16+
- **[neaps](packages/neaps)** - Main tide prediction library with station finding
17+
- **[@neaps/api](packages/api)** - HTTP JSON API for tide predictions with OpenAPI specification
18+
- **[@neaps/tide-predictor](packages/tide-predictor)** - Core harmonic tide prediction engine
19+
1220
## Installation
1321

1422
```sh

eslint.config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import eslint from "@eslint/js";
22
import tseslint from "typescript-eslint";
33
import prettier from "eslint-config-prettier";
4+
import globals from "globals";
45

56
export default [
67
{ ignores: ["dist/", "node_modules/", "packages/*/dist"] },
78
eslint.configs.recommended,
89
...tseslint.configs.recommended,
910
prettier,
1011
{ files: ["**/*.ts"], languageOptions: { parser: tseslint.parser } },
11-
{ files: ["**/*.js"] },
12+
{
13+
files: ["packages/api/**/*.{js,ts}"],
14+
languageOptions: {
15+
globals: globals.node,
16+
},
17+
},
1218
];

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@vitest/coverage-v8": "^4.0.15",
1717
"eslint": "^9.39.2",
1818
"eslint-config-prettier": "^10.1.8",
19+
"globals": "^17.2.0",
1920
"make-fetch-happen": "^15.0.3",
2021
"npm-run-all": "^4.1.5",
2122
"prettier": "^3.7.4",
@@ -25,6 +26,8 @@
2526
"vitest": "^4.0.15"
2627
},
2728
"workspaces": [
28-
"packages/*"
29+
"packages/tide-predictor",
30+
"packages/neaps",
31+
"packages/api"
2932
]
3033
}

packages/api/README.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# @neaps/api
2+
3+
HTTP JSON API for tide predictions using [neaps](https://github.com/neaps/neaps).
4+
5+
## Installation
6+
7+
```bash
8+
npm install @neaps/api
9+
```
10+
11+
## Usage
12+
13+
### As a standalone server
14+
15+
```typescript
16+
import { createApp } from "@neaps/api";
17+
18+
const app = createApp();
19+
20+
app.listen(3000, () => {
21+
console.log("Server listening on port 3000");
22+
});
23+
```
24+
25+
### As an Express middleware
26+
27+
```typescript
28+
import { createApp } from "@neaps/api";
29+
import express from "express";
30+
31+
const mainApp = express();
32+
33+
// Mount the API at a specific path
34+
mainApp.use("/api", createApp());
35+
36+
mainApp.listen(3000, () => {
37+
console.log("Server listening on port 3000");
38+
});
39+
```
40+
41+
## API Endpoints
42+
43+
### GET /tides/extremes
44+
45+
Get high and low tide predictions for the nearest station to given coordinates.
46+
47+
**Query Parameters:**
48+
49+
- `latitude` (required): Latitude (-90 to 90)
50+
- `longitude` (required): Longitude (-180 to 180)
51+
- `start` (required): Start date/time in ISO 8601 format
52+
- `end` (required): End date/time in ISO 8601 format
53+
- `datum` (optional): Vertical datum (MLLW, MLW, MTL, MSL, MHW, MHHW)
54+
- `units` (optional): Units for water levels (meters or feet, defaults to meters)
55+
56+
**Example:**
57+
58+
```bash
59+
curl "http://localhost:3000/tides/extremes?latitude=26.772&longitude=-80.05&start=2025-12-17T00:00:00Z&end=2025-12-18T00:00:00Z&datum=MLLW&units=feet"
60+
```
61+
62+
### GET /tides/timeline
63+
64+
Get water level predictions at regular intervals for the nearest station.
65+
66+
**Query Parameters:** Same as `/extremes`
67+
68+
**Example:**
69+
70+
```bash
71+
curl "http://localhost:3000/tides/timeline?latitude=26.772&longitude=-80.05&start=2025-12-17T00:00:00Z&end=2025-12-18T00:00:00Z"
72+
```
73+
74+
### GET /tides/stations
75+
76+
Find stations by ID or near a location.
77+
78+
**Query Parameters:**
79+
80+
- `id` (optional): Station ID or source ID
81+
- `latitude` (optional): Latitude for proximity search
82+
- `longitude` (optional): Longitude for proximity search
83+
- `limit` (optional): Maximum number of stations to return (1-100, defaults to 10)
84+
85+
**Examples:**
86+
87+
```bash
88+
# Find a specific station
89+
curl "http://localhost:3000/tides/stations?id=noaa/8722588"
90+
91+
# Find stations near coordinates
92+
curl "http://localhost:3000/tides/stations?latitude=26.772&longitude=-80.05&limit=5"
93+
```
94+
95+
### GET /tides/stations/:id/extremes
96+
97+
Get extremes prediction for a specific station.
98+
99+
**Path Parameters:**
100+
101+
- `id` (required): Station ID (URL-encoded if contains special characters)
102+
103+
**Query Parameters:**
104+
105+
- `start` (required): Start date/time in ISO 8601 format
106+
- `end` (required): End date/time in ISO 8601 format
107+
- `datum` (optional): Vertical datum
108+
- `units` (optional): Units for water levels
109+
110+
**Example:**
111+
112+
```bash
113+
curl "http://localhost:3000/tides/stations/noaa%2F8722588/extremes?start=2025-12-17T00:00:00Z&end=2025-12-18T00:00:00Z"
114+
```
115+
116+
### GET /tides/stations/:id/timeline
117+
118+
Get timeline prediction for a specific station.
119+
120+
**Parameters:** Same as `/stations/:id/extremes`
121+
122+
**Note:** Timeline predictions are not supported for subordinate stations.
123+
124+
### GET /tides/openapi.json
125+
126+
Get the OpenAPI 3.0 specification for this API.
127+
128+
## Development
129+
130+
```bash
131+
# Install dependencies
132+
npm install
133+
134+
# Build
135+
npm run build
136+
137+
# Run tests
138+
npx vitest
139+
140+
# Run tests with coverage
141+
npx vitest run --coverage
142+
```
143+
144+
## License
145+
146+
MIT

packages/api/bin/server.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env node
2+
3+
import { createApp } from "@neaps/api";
4+
5+
const port = process.env.PORT || 3000;
6+
const app = createApp();
7+
8+
app.listen(port, () => {
9+
console.log(`Neaps API listening on http://localhost:${port}`);
10+
});

packages/api/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@neaps/api",
3+
"version": "0.2.0",
4+
"description": "HTTP JSON API for tide predictions",
5+
"repository": {
6+
"type": "git",
7+
"url": "git+https://github.com/neaps/neaps.git",
8+
"directory": "packages/api"
9+
},
10+
"author": "Brandon Keepers <brandon@openwaters.io>",
11+
"license": "MIT",
12+
"type": "module",
13+
"types": "./dist/index.d.mts",
14+
"exports": {
15+
".": "./dist/index.mjs",
16+
"./package.json": "./package.json"
17+
},
18+
"files": [
19+
"dist"
20+
],
21+
"bin": {
22+
"neaps-server": "./bin/server.js"
23+
},
24+
"scripts": {
25+
"build": "tsc && tsdown",
26+
"prepack": "npm run build",
27+
"start": "node bin/server.js"
28+
},
29+
"dependencies": {
30+
"express": "^4.18.2",
31+
"express-openapi-validator": "^5.1.6",
32+
"neaps": "^0.3.0"
33+
},
34+
"devDependencies": {
35+
"@types/express": "^4.17.21",
36+
"@types/supertest": "^6.0.2",
37+
"supertest": "^6.3.3"
38+
}
39+
}

packages/api/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import express from "express";
2+
import routes from "./routes.js";
3+
import openapi from "./openapi.js";
4+
5+
export function createApp() {
6+
return express().use("/", routes);
7+
}
8+
9+
export { routes, openapi };

0 commit comments

Comments
 (0)