Skip to content

Commit 045961f

Browse files
remove bounds endpoints (#1256)
* remove bounds endpoints * fix tests
1 parent 9f7d81d commit 045961f

File tree

14 files changed

+42
-219
lines changed

14 files changed

+42
-219
lines changed

CHANGES.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
## Unreleased
44

5+
### Misc
6+
7+
* remove `/bounds` endpoints **breaking change**
8+
* update docker image to python:3.13
9+
* switch to `uv` for development
10+
* switch to `hatch` for python package build-system
11+
* remove `titiler` metapackage **breaking change**
12+
* bump minimum python version to 3.11
13+
514
### titiler.xarray
615

716
* add `opener_options` arg to `titiler.xarray.io.Reader` to allow users to pass args through to a custom opener function ([#1248(https://github.com/developmentseed/titiler/pull/1248)])
@@ -11,14 +20,6 @@
1120
* add `FsReader` which use `fs_open_dataset` as `dataset_opener`
1221
* create offical application `titiler.xarray.main:app`
1322

14-
### Misc
15-
16-
* update docker image to python:3.13
17-
* switch to `uv` for development
18-
* switch to `hatch` for python package build-system
19-
* remove `titiler` metapackage **breaking change**
20-
* bump minimum python version to 3.11
21-
2223
## 0.24.2 (2025-10-16)
2324

2425
### titiler.core

docs/src/advanced/endpoints_factories.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ app.include_router(cog.router)
8585

8686
| Method | URL | Output | Description
8787
| ------ | --------------------------------------------------------------- |-------------------------------------------- |--------------
88-
| `GET` | `/bounds` | JSON ([Bounds][bounds_model]) | return dataset's bounds
8988
| `GET` | `/info` | JSON ([Info][info_model]) | return dataset's basic info
9089
| `GET` | `/info.geojson` | GeoJSON ([InfoGeoJSON][info_geojson_model]) | return dataset's basic info as a GeoJSON feature
9190
| `GET` | `/statistics` | JSON ([Statistics][stats_model]) | return dataset's statistics
@@ -137,7 +136,6 @@ app.include_router(stac.router)
137136

138137
| Method | URL | Output | Description
139138
| ------ | --------------------------------------------------------------- |------------------------------------------------- |--------------
140-
| `GET` | `/bounds` | JSON ([Bounds][bounds_model]) | return dataset's bounds
141139
| `GET` | `/assets` | JSON | return the list of available assets
142140
| `GET` | `/info` | JSON ([Info][multiinfo_model]) | return assets basic info
143141
| `GET` | `/info.geojson` | GeoJSON ([InfoGeoJSON][multiinfo_geojson_model]) | return assets basic info as a GeoJSON feature
@@ -195,7 +193,6 @@ app.include_router(landsat.router)
195193

196194
| Method | URL | Output | Description
197195
| ------ | --------------------------------------------------------------- |--------------------------------------------- |--------------
198-
| `GET` | `/bounds` | JSON ([Bounds][bounds_model]) | return dataset's bounds
199196
| `GET` | `/bands` | JSON | return the list of available bands
200197
| `GET` | `/info` | JSON ([Info][info_model]) | return basic info for a dataset
201198
| `GET` | `/info.geojson` | GeoJSON ([InfoGeoJSON][info_geojson_model]) | return basic info for a dataset as a GeoJSON feature
@@ -333,7 +330,6 @@ Endpoints factory for mosaics, built on top of [MosaicJSON](https://github.com/d
333330
| Method | URL | Output | Description
334331
| ------ | --------------------------------------------------------------- |--------------------------------------------------- |--------------
335332
| `GET` | `/` | JSON [MosaicJSON][mosaic_model] | return a MosaicJSON document
336-
| `GET` | `/bounds` | JSON ([Bounds][bounds_model]) | return mosaic's bounds
337333
| `GET` | `/info` | JSON ([Info][mosaic_info_model]) | return mosaic's basic info
338334
| `GET` | `/info.geojson` | GeoJSON ([InfoGeoJSON][mosaic_geojson_info_model]) | return mosaic's basic info as a GeoJSON feature
339335
| `GET` | `/tiles` | JSON | List of OGC Tilesets available
@@ -398,7 +394,6 @@ app.include_router(md.router)
398394

399395
| Method | URL | Output | Description
400396
| ------ | --------------------------------------------------------------- |-------------------------------------------- |--------------
401-
| `GET` | `/bounds` | JSON ([Bounds][bounds_model]) | return dataset's bounds
402397
| `GET` | `/info` | JSON ([Info][info_model]) | return dataset's basic info
403398
| `GET` | `/info.geojson` | GeoJSON ([InfoGeoJSON][info_geojson_model]) | return dataset's basic info as a GeoJSON feature
404399
| `POST` | `/statistics` | GeoJSON ([Statistics][stats_geojson_model]) | return dataset's statistics for a GeoJSON

docs/src/endpoints/cog.md

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ The `/cog` routes are based on `titiler.core.factory.TilerFactory` but with `cog
99

1010
| Method | URL | Output | Description
1111
| ------ | ------------------------------------------------------------------- |---------- |--------------
12-
| `GET` | `/cog/bounds` | JSON | return dataset's bounds
1312
| `GET` | `/cog/info` | JSON | return dataset's basic info
1413
| `GET` | `/cog/info.geojson` | GeoJSON | return dataset's basic info as a GeoJSON feature
1514
| `GET` | `/cog/statistics` | JSON | return dataset's statistics
@@ -313,18 +312,6 @@ Example:
313312
- `https://myendpoint/cog/WorldCRS84Quad/map.html?url=https://somewhere.com/mycog.tif&tile_scale=2&bidx=1,2,3`
314313

315314

316-
### Bounds
317-
318-
`:endpoint:/cog/bounds` general image bounds
319-
320-
- QueryParams:
321-
- **url** (str): Cloud Optimized GeoTIFF URL. **Required**
322-
- **crs** (str): Geographic Coordinate Reference System. Default to `epsg:4326`.
323-
324-
Example:
325-
326-
- `https://myendpoint/cog/bounds?url=https://somewhere.com/mycog.tif`
327-
328315
### Info
329316

330317
`:endpoint:/cog/info` general raster info

docs/src/endpoints/mosaic.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Read Mosaic Info/Metadata and create Web map Tiles from a multiple COG. The `mos
1010
| Method | URL | Output | Description
1111
| ------ | -------------------------------------------------------------------------- |---------- |--------------
1212
| `GET` | `/mosaicjson/` | JSON | return a MosaicJSON document
13-
| `GET` | `/mosaicjson/bounds` | JSON | return mosaic's bounds
1413
| `GET` | `/mosaicjson/info` | JSON | return mosaic's basic info
1514
| `GET` | `/mosaicjson/info.geojson` | GeoJSON | return mosaic's basic info as a GeoJSON feature
1615
| `GET` | `/mosaicjson/tiles` | JSON | List of OGC Tilesets available

docs/src/endpoints/stac.md

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ The `/stac` routes are based on `titiler.core.factory.MultiBaseTilerFactory` but
1010
| Method | URL | Output | Description
1111
| ------ | -------------------------------------------------------------------- |---------- |--------------
1212
| `GET` | `/stac/assets` | JSON | return available assets within the STAC item
13-
| `GET` | `/stac/bounds` | JSON | return STAC item bounds
1413
| `GET` | `/stac/info` | JSON | return asset's basic info
1514
| `GET` | `/stac/info.geojson` | GeoJSON | return asset's basic info as a GeoJSON feature
1615
| `GET` | `/stac/asset_statistics` | JSON | return per asset statistics
@@ -346,19 +345,6 @@ Example:
346345
- `https://myendpoint/stac/WorldCRS84Quad/tilejson.json?url=https://somewhere.com/item.json&tile_scale=2&expression=B01/B02`
347346

348347

349-
### Bounds
350-
351-
`:endpoint:/stac/bounds` - Return the bounds of the STAC item.
352-
353-
- QueryParams:
354-
- **url** (str): STAC Item URL. **Required**
355-
- **crs** (str): Geographic Coordinate Reference System. Default to `epsg:4326`.
356-
357-
Example:
358-
359-
- `https://myendpoint/stac/bounds?url=https://somewhere.com/item.json`
360-
361-
362348
### Info
363349

364350
`:endpoint:/stac/info` - Return basic info on STAC item's COG.

docs/src/user_guide/getting_started.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -220,28 +220,28 @@ The following code (in **map.html**) loads a base map, adds your TiTiler raster
220220
/// Define the local raster path and TiTiler endpoint
221221
// Replace with your own full GeoTIFF path - use the appropriate format for your OS.
222222
var rasterPath = 'file:///path_to_your_raster.tif';
223-
var titilerUrl = 'http://127.0.0.1:8000/tiles/WebMercatorQuad/{z}/{x}/{y}.png?url=' + encodeURIComponent(rasterPath);
224-
225-
// Add the TiTiler raster overlay with some transparency
226-
L.tileLayer(titilerUrl, {
227-
tileSize: 256,
228-
opacity: 0.7,
229-
maxZoom: 22
230-
}).addTo(map);
231223
232224
// Fetch the raster's bounding box from TiTiler and adjust the map view accordingly
233-
var boundsUrl = 'http://127.0.0.1:8000/bounds?url=' + encodeURIComponent(rasterPath);
234-
console.log(boundsUrl)
235-
fetch(boundsUrl)
225+
var tileJSONUrl = 'http://127.0.0.1:8000/WebMercatorQuad/tilejson.json?url=' + encodeURIComponent(rasterPath);
226+
console.log(tileJSONUrl)
227+
fetch(tileJSONUrl)
236228
.then(response => response.json())
237229
.then(data => {
238-
console.log("Bounds data:", data);
230+
console.log("Bounds data:", data.bounds);
239231
if (data && data.bounds) {
240232
// data.bounds is [minX, minY, maxX, maxY]
241233
var b = data.bounds;
242234
// Convert to Leaflet bounds: [[southWest_lat, southWest_lng], [northEast_lat, northEast_lng]]
243235
var leafletBounds = [[b[1], b[0]], [b[3], b[2]]];
244236
map.fitBounds(leafletBounds);
237+
238+
// Add the TiTiler raster overlay with some transparency
239+
L.tileLayer(data.tiles[0], {
240+
tileSize: 256,
241+
opacity: 0.7,
242+
maxZoom: data.maxzoom
243+
}).addTo(map);
244+
245245
} else {
246246
console.error("No bounds returned from TiTiler.");
247247
}

src/titiler/application/tests/routes/test_cog.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,6 @@
1212
from ..conftest import DATA_DIR, mock_rasterio_open, parse_img
1313

1414

15-
@patch("rio_tiler.io.rasterio.rasterio")
16-
def test_bounds(rio, app):
17-
"""test /bounds endpoint."""
18-
rio.open = mock_rasterio_open
19-
20-
response = app.get("/cog/bounds?url=https://myurl.com/cog.tif")
21-
assert response.status_code == 200
22-
body = response.json()
23-
assert len(body["bounds"]) == 4
24-
assert response.headers["Cache-Control"] == "private, max-age=3600"
25-
26-
2715
@patch("rio_tiler.io.rasterio.rasterio")
2816
def test_info(rio, app):
2917
"""test /info endpoint."""

src/titiler/application/tests/routes/test_mosaic.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,6 @@ def test_read_mosaic(app):
4242
MosaicJSON(**response.json())
4343

4444

45-
def test_bounds(app):
46-
"""test GET /mosaicjson/bounds endpoint"""
47-
response = app.get("/mosaicjson/bounds", params={"url": MOSAICJSON_FILE})
48-
assert response.status_code == 200
49-
body = response.json()
50-
assert len(body["bounds"]) == 4
51-
assert body["bounds"][0] < body["bounds"][2]
52-
assert body["bounds"][1] < body["bounds"][3]
53-
54-
5545
def test_info(app):
5646
"""test GET /mosaicjson/info endpoint"""
5747
response = app.get("/mosaicjson/info", params={"url": MOSAICJSON_FILE})

src/titiler/application/tests/routes/test_stac.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@
99
from ..conftest import mock_rasterio_open, mock_RequestGet
1010

1111

12-
@patch("rio_tiler.io.stac.httpx")
13-
def test_bounds(httpx, app):
14-
"""test /bounds endpoint."""
15-
httpx.get = mock_RequestGet
16-
17-
response = app.get("/stac/bounds?url=https://myurl.com/item.json")
18-
assert response.status_code == 200
19-
body = response.json()
20-
assert len(body["bounds"]) == 4
21-
22-
2312
@patch("rio_tiler.io.rasterio.rasterio")
2413
@patch("rio_tiler.io.stac.httpx")
2514
def test_info(httpx, rio, app):

src/titiler/core/tests/test_factories.py

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
def test_TilerFactory():
5252
"""Test TilerFactory class."""
5353
cog = TilerFactory()
54-
assert len(cog.router.routes) == 23
54+
assert len(cog.router.routes) == 22
5555
assert len(cog.supported_tms.list()) == NB_DEFAULT_TMS
5656

5757
cog = TilerFactory(router_prefix="something", supported_tms=WEB_TMS)
@@ -78,7 +78,7 @@ def test_TilerFactory():
7878
assert response.status_code == 422
7979

8080
cog = TilerFactory(add_preview=False, add_part=False, add_viewer=False)
81-
assert len(cog.router.routes) == 14
81+
assert len(cog.router.routes) == 13
8282

8383
app = FastAPI()
8484
cog = TilerFactory()
@@ -314,12 +314,6 @@ def test_TilerFactory():
314314
root = ET.fromstring(response.content)
315315
assert root is not None
316316

317-
response = client.get(f"/bounds?url={DATA_DIR}/cog.tif")
318-
assert response.status_code == 200
319-
assert response.headers["content-type"] == "application/json"
320-
assert len(response.json()["bounds"]) == 4
321-
assert response.json()["crs"]
322-
323317
response = client.get(f"/info?url={DATA_DIR}/cog.tif")
324318
assert response.status_code == 200
325319
assert response.headers["content-type"] == "application/json"
@@ -783,7 +777,7 @@ def test_MultiBaseTilerFactory(rio):
783777
rio.open = mock_rasterio_open
784778

785779
stac = MultiBaseTilerFactory(reader=STACReader)
786-
assert len(stac.router.routes) == 25
780+
assert len(stac.router.routes) == 24
787781

788782
app = FastAPI()
789783
app.include_router(stac.router)
@@ -802,11 +796,6 @@ def test_MultiBaseTilerFactory(rio):
802796
assert response.status_code == 200
803797
assert len(response.json()) == 2
804798

805-
response = client.get(f"/bounds?url={DATA_DIR}/item.json")
806-
assert response.status_code == 200
807-
assert len(response.json()["bounds"]) == 4
808-
assert response.json()["crs"]
809-
810799
# no assets
811800
with pytest.warns(UserWarning):
812801
response = client.get(f"/info?url={DATA_DIR}/item.json")
@@ -1173,7 +1162,7 @@ def test_MultiBandTilerFactory():
11731162
bands = MultiBandTilerFactory(
11741163
reader=BandFileReader, path_dependency=CustomPathParams
11751164
)
1176-
assert len(bands.router.routes) == 24
1165+
assert len(bands.router.routes) == 23
11771166

11781167
app = FastAPI()
11791168
app.include_router(bands.router)
@@ -1558,15 +1547,15 @@ def must_be_bob(credentials: security.HTTPBasicCredentials = Depends(http_basic)
15581547
route_dependencies=[
15591548
(
15601549
[
1561-
{"path": "/bounds", "method": "GET"},
1550+
{"path": "/info", "method": "GET"},
15621551
{"path": "/tiles/{tileMatrixSetId}/{z}/{x}/{y}", "method": "GET"},
15631552
],
15641553
[Depends(must_be_bob)],
15651554
),
15661555
],
15671556
router_prefix="something",
15681557
)
1569-
assert len(cog.router.routes) == 23
1558+
assert len(cog.router.routes) == 22
15701559

15711560
app = FastAPI()
15721561
app.include_router(cog.router, prefix="/something")
@@ -1582,14 +1571,10 @@ def must_be_bob(credentials: security.HTTPBasicCredentials = Depends(http_basic)
15821571
assert response.headers["content-type"] == "application/json"
15831572
assert response.json()["tilejson"]
15841573

1585-
response = client.get(
1586-
f"/something/bounds?url={DATA_DIR}/cog.tif&rescale=0,1000", auth=auth_bob
1587-
)
1574+
response = client.get(f"/something/info?url={DATA_DIR}/cog.tif", auth=auth_bob)
15881575
assert response.status_code == 200
15891576

1590-
response = client.get(
1591-
f"/something/bounds?url={DATA_DIR}/cog.tif&rescale=0,1000", auth=auth_notbob
1592-
)
1577+
response = client.get(f"/something/info?url={DATA_DIR}/cog.tif", auth=auth_notbob)
15931578
assert response.status_code == 401
15941579
assert response.json()["detail"] == "You're not Bob"
15951580

@@ -1615,7 +1600,7 @@ def must_be_bob(credentials: security.HTTPBasicCredentials = Depends(http_basic)
16151600

16161601
cog = TilerFactory(router_prefix="something")
16171602
cog.add_route_dependencies(
1618-
scopes=[{"path": "/bounds", "method": "GET"}],
1603+
scopes=[{"path": "/info", "method": "GET"}],
16191604
dependencies=[Depends(must_be_bob)],
16201605
)
16211606

@@ -1630,14 +1615,10 @@ def must_be_bob(credentials: security.HTTPBasicCredentials = Depends(http_basic)
16301615
assert response.headers["content-type"] == "application/json"
16311616
assert response.json()["tilejson"]
16321617

1633-
response = client.get(
1634-
f"/something/bounds?url={DATA_DIR}/cog.tif&rescale=0,1000", auth=auth_bob
1635-
)
1618+
response = client.get(f"/something/info?url={DATA_DIR}/cog.tif", auth=auth_bob)
16361619
assert response.status_code == 200
16371620

1638-
response = client.get(
1639-
f"/something/bounds?url={DATA_DIR}/cog.tif&rescale=0,1000", auth=auth_notbob
1640-
)
1621+
response = client.get(f"/something/info?url={DATA_DIR}/cog.tif", auth=auth_notbob)
16411622
assert response.status_code == 401
16421623
assert response.json()["detail"] == "You're not Bob"
16431624

@@ -2088,7 +2069,7 @@ def test_ogc_maps_cog():
20882069
cog_path = f"{DATA_DIR}/cog.tif"
20892070

20902071
cog = TilerFactory(add_ogc_maps=True)
2091-
assert len(cog.router.routes) == 24
2072+
assert len(cog.router.routes) == 23
20922073

20932074
assert "https://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/core" in cog.conforms_to
20942075

0 commit comments

Comments
 (0)