Skip to content

Commit 9019ca0

Browse files
authored
Merge branch 'main' into docs/getting-started-nb
2 parents 821d17b + 80a7255 commit 9019ca0

File tree

22 files changed

+714
-383
lines changed

22 files changed

+714
-383
lines changed

.github/workflows/tests/test_raster.py

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,61 @@ def test_raster_api():
1616
def test_mosaic_api():
1717
"""test mosaic."""
1818
query = {"collections": ["noaa-emergency-response"], "filter-lang": "cql-json"}
19-
resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=query)
19+
resp = httpx.post(f"{raster_endpoint}/searches/register", json=query)
2020
assert resp.headers["content-type"] == "application/json"
2121
assert resp.status_code == 200
22-
assert resp.json()["searchid"]
22+
assert resp.json()["id"]
2323
assert resp.json()["links"]
2424

25-
searchid = resp.json()["searchid"]
25+
searchid = resp.json()["id"]
2626

27-
resp = httpx.get(f"{raster_endpoint}/mosaic/{searchid}/-85.6358,36.1624/assets")
27+
resp = httpx.get(f"{raster_endpoint}/searches/{searchid}/-85.6358,36.1624/assets")
2828
assert resp.status_code == 200
2929
assert len(resp.json()) == 1
3030
assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"]
3131
assert resp.json()[0]["id"] == "20200307aC0853900w361030"
3232

33-
resp = httpx.get(f"{raster_endpoint}/mosaic/{searchid}/tiles/15/8589/12849/assets")
33+
resp = httpx.get(
34+
f"{raster_endpoint}/searches/{searchid}/tiles/15/8589/12849/assets"
35+
)
3436
assert resp.status_code == 200
3537
assert len(resp.json()) == 1
3638
assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"]
3739
assert resp.json()[0]["id"] == "20200307aC0853900w361030"
3840

3941
z, x, y = 15, 8589, 12849
4042
resp = httpx.get(
41-
f"{raster_endpoint}/mosaic/{searchid}/tiles/{z}/{x}/{y}",
43+
f"{raster_endpoint}/searches/{searchid}/tiles/{z}/{x}/{y}",
44+
params={"assets": "cog"},
45+
headers={"Accept-Encoding": "br, gzip"},
46+
timeout=10.0,
47+
)
48+
assert resp.status_code == 200
49+
assert resp.headers["content-type"] == "image/jpeg"
50+
assert "content-encoding" not in resp.headers
51+
52+
53+
def test_mosaic_collection_api():
54+
"""test mosaic collection."""
55+
resp = httpx.get(
56+
f"{raster_endpoint}/collections/noaa-emergency-response/-85.6358,36.1624/assets"
57+
)
58+
assert resp.status_code == 200
59+
assert len(resp.json()) == 1
60+
assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"]
61+
assert resp.json()[0]["id"] == "20200307aC0853900w361030"
62+
63+
resp = httpx.get(
64+
f"{raster_endpoint}/collections/noaa-emergency-response/tiles/15/8589/12849/assets"
65+
)
66+
assert resp.status_code == 200
67+
assert len(resp.json()) == 1
68+
assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"]
69+
assert resp.json()[0]["id"] == "20200307aC0853900w361030"
70+
71+
z, x, y = 15, 8589, 12849
72+
resp = httpx.get(
73+
f"{raster_endpoint}/collections/noaa-emergency-response/tiles/{z}/{x}/{y}",
4274
params={"assets": "cog"},
4375
headers={"Accept-Encoding": "br, gzip"},
4476
timeout=10.0,
@@ -102,11 +134,11 @@ def test_mosaic_search():
102134
},
103135
]
104136
for search in searches:
105-
resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=search)
137+
resp = httpx.post(f"{raster_endpoint}/searches/register", json=search)
106138
assert resp.status_code == 200
107-
assert resp.json()["searchid"]
139+
assert resp.json()["id"]
108140

109-
resp = httpx.get(f"{raster_endpoint}/mosaic/list")
141+
resp = httpx.get(f"{raster_endpoint}/searches/list")
110142
assert resp.headers["content-type"] == "application/json"
111143
assert resp.status_code == 200
112144
assert (
@@ -122,9 +154,11 @@ def test_mosaic_search():
122154
assert len(links) == 2
123155
assert links[0]["rel"] == "self"
124156
assert links[1]["rel"] == "next"
125-
assert links[1]["href"] == f"{raster_endpoint}/mosaic/list?limit=10&offset=10"
157+
assert links[1]["href"] == f"{raster_endpoint}/searches/list?limit=10&offset=10"
126158

127-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"limit": 1, "offset": 1})
159+
resp = httpx.get(
160+
f"{raster_endpoint}/searches/list", params={"limit": 1, "offset": 1}
161+
)
128162
assert resp.status_code == 200
129163
assert resp.json()["context"]["matched"] > 10
130164
assert resp.json()["context"]["limit"] == 1
@@ -133,33 +167,33 @@ def test_mosaic_search():
133167
links = resp.json()["links"]
134168
assert len(links) == 3
135169
assert links[0]["rel"] == "self"
136-
assert links[0]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=1"
170+
assert links[0]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=1"
137171
assert links[1]["rel"] == "next"
138-
assert links[1]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=2"
172+
assert links[1]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=2"
139173
assert links[2]["rel"] == "prev"
140-
assert links[2]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=0"
174+
assert links[2]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=0"
141175

142176
# Filter on mosaic metadata
143-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"owner": "vincent"})
177+
resp = httpx.get(f"{raster_endpoint}/searches/list", params={"owner": "vincent"})
144178
assert resp.status_code == 200
145179
assert resp.json()["context"]["matched"] == 7
146180
assert resp.json()["context"]["limit"] == 10
147181
assert resp.json()["context"]["returned"] == 7
148182

149183
# sortBy
150-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "lastused"})
184+
resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "lastused"})
151185
assert resp.status_code == 200
152186

153-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "usecount"})
187+
resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "usecount"})
154188
assert resp.status_code == 200
155189

156-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "-owner"})
190+
resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "-owner"})
157191
assert resp.status_code == 200
158192
assert (
159193
"owner" not in resp.json()["searches"][0]["search"]["metadata"]
160194
) # some mosaic don't have owners
161195

162-
resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "owner"})
196+
resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "owner"})
163197
assert resp.status_code == 200
164198
assert "owner" in resp.json()["searches"][0]["search"]["metadata"]
165199

@@ -201,3 +235,15 @@ def test_collections():
201235
collections = resp.json()
202236
assert len(collections) == 1
203237
assert collections[0]["id"] == "noaa-emergency-response"
238+
239+
240+
def test_cog_endpoints():
241+
"""test /cog endpoints"""
242+
resp = httpx.get(
243+
f"{raster_endpoint}/cog/info",
244+
params={
245+
"url": "https://noaa-eri-pds.s3.us-east-1.amazonaws.com/2020_Nashville_Tornado/20200307a_RGB/20200307aC0854500w361030n.tif",
246+
},
247+
)
248+
assert resp.status_code == 200
249+
assert resp.headers["content-type"] == "application/json"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,8 @@ node_modules/
113113

114114
# Demo files to ignore
115115
demo/cmip6/CMIP6_daily_*stac_items.ndjson
116+
117+
118+
# browser compiled code and default config
119+
infrastructure/aws/stac-browser
120+
infrastructure/aws/browser_config.js

README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
- **OGC Features and Vector Tiles** API built on top of [https://github.com/developmentseed/tipg](https://github.com/developmentseed/tipg)
3434

35+
- **A STAC Catalog browsing UI** based on the radiant earth browser : [https://github.com/radiantearth/stac-browser](https://github.com/radiantearth/stac-browser)
36+
3537
---
3638

3739
## 🌍 eoAPI: An Open-Source Community Project
@@ -57,22 +59,19 @@ Then you can start exploring your dataset with:
5759

5860
- the STAC Metadata service [http://localhost:8081](http://localhost:8081)
5961
- the Raster service [http://localhost:8082](http://localhost:8082)
62+
- the browser UI [http://localhost:8085](http://localhost:8085)
6063

6164
If you've added a vector dataset to the `public` schema in the Postgres database, they will be available through the **Vector** service at [http://localhost:8083](http://localhost:8083).
6265

63-
## Deployment
66+
## Deployment with standard runtimes
6467

6568
This repository has current runtimes that are consistently updated with new functionality.
6669

67-
The services can be deployed locally via docker with `docker compose up`.
68-
69-
Two Infrastructure as Code (IaC) repositories are available:
70-
- [eoapi-cdk](https://github.com/developmentseed/eoapi-cdk): A set of AWS CDK constructs to deploy eoAPI services
71-
- [eoapi-k8s](https://github.com/developmentseed/eoapi-k8s): IaC and Helm charts for deploying eoAPI services on AWS and GCP
70+
### Local deployment
7271

73-
Finally, [eoapi-template](https://github.com/developmentseed/eoapi-template) is an AWS CDK app that shows how to configure the eoapi-cdk constructs.
72+
The services can be deployed altogether locally with `docker compose up`.
7473

75-
Alternatively, you may install the libraries locally:
74+
Alternatively, you may install the libraries and launch the applications manually :
7675

7776
<details>
7877

@@ -109,7 +108,19 @@ Note: python libraries might have incompatible dependencies, which you can resol
109108

110109
</details>
111110

112-
## Custom runtimes
111+
### Deployment on the cloud
112+
113+
#### Kubernetes
114+
115+
[eoapi-k8s](https://github.com/developmentseed/eoapi-k8s) contains IaC and Helm charts for deploying eoAPI services on AWS and GCP.
116+
117+
#### AWS CDK
118+
119+
[eoapi-cdk](https://github.com/developmentseed/eoapi-cdk) defines a set of AWS CDK constructs that can be used to deploy eoAPI services on AWS. This repository itself makes use of these in `infrastructure/aws`. An official example usage of these constructs can be found at [eoapi-template](https://github.com/developmentseed/eoapi-template).
120+
121+
122+
123+
## Deployment with custom runtimes
113124

114125
The eoAPI repository hosts customized versions of each base service which can work in parallel or in combination with each other.
115126

docker-compose.custom.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
version: '3'
22

33
services:
4+
stac-browser:
5+
profiles:
6+
- gunicorn
7+
build:
8+
context: dockerfiles
9+
dockerfile: Dockerfile.browser
10+
ports:
11+
- "${MY_DOCKER_IP:-127.0.0.1}:8085:8085"
12+
depends_on:
13+
- stac
14+
- database
15+
- raster
416
stac:
517
container_name: eoapi.stac
618
profiles:
@@ -34,6 +46,9 @@ services:
3446
# https://github.com/developmentseed/eoAPI/issues/16
3547
# - TITILER_ENDPOINT=raster
3648
- TITILER_ENDPOINT=http://127.0.0.1:8082
49+
# PgSTAC extensions
50+
# - EOAPI_STAC_EXTENSIONS=["filter", "query", "sort", "fields", "pagination", "context", "transaction"]
51+
# - EOAPI_STAC_CORS_METHODS='GET,POST,PUT,OPTIONS'
3752
depends_on:
3853
- database
3954
- raster
@@ -159,6 +174,9 @@ services:
159174
# https://github.com/developmentseed/eoAPI/issues/16
160175
# - TITILER_ENDPOINT=raster
161176
- TITILER_ENDPOINT=http://127.0.0.1:8082
177+
# PgSTAC extensions
178+
# - EOAPI_STAC_EXTENSIONS=["filter", "query", "sort", "fields", "pagination", "context", "transaction"]
179+
# - EOAPI_STAC_CORS_METHODS='GET,POST,PUT,OPTIONS'
162180
depends_on:
163181
- database
164182
- raster-uvicorn

docker-compose.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
version: '3'
22

33
services:
4+
5+
# change to official image when available https://github.com/radiantearth/stac-browser/pull/386
6+
stac-browser:
7+
build:
8+
context: dockerfiles
9+
dockerfile: Dockerfile.browser
10+
ports:
11+
- "${MY_DOCKER_IP:-127.0.0.1}:8085:8085"
12+
depends_on:
13+
- stac-fastapi
14+
- titiler-pgstac
15+
- database
16+
417
stac-fastapi:
518
# Note:
619
# the official ghcr.io/stac-utils/stac-fastapi-pgstac image uses python 3.8 and uvicorn
@@ -43,7 +56,7 @@ services:
4356
# At the time of writing, rasterio and psycopg wheels are not available for arm64 arch
4457
# so we force the image to be built with linux/amd64
4558
platform: linux/amd64
46-
image: ghcr.io/stac-utils/titiler-pgstac:0.8.0
59+
image: ghcr.io/stac-utils/titiler-pgstac:1.0.0a3
4760
ports:
4861
- "${MY_DOCKER_IP:-127.0.0.1}:8082:8082"
4962
environment:
@@ -89,7 +102,7 @@ services:
89102
- ./dockerfiles/scripts:/tmp/scripts
90103

91104
tipg:
92-
image: ghcr.io/developmentseed/tipg:0.4.4
105+
image: ghcr.io/developmentseed/tipg:0.5.0
93106
ports:
94107
- "${MY_DOCKER_IP:-127.0.0.1}:8083:8083"
95108
environment:

dockerfiles/Dockerfile.browser

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright Radiant Earth Foundation
2+
3+
FROM node:lts-alpine3.18 AS build-step
4+
ARG DYNAMIC_CONFIG=true
5+
6+
WORKDIR /app
7+
8+
RUN apk add --no-cache git
9+
RUN git clone https://github.com/radiantearth/stac-browser.git .
10+
# remove the default config.js
11+
RUN rm config.js
12+
RUN npm install
13+
# replace the default config.js with our config file
14+
COPY ./browser_config.js ./config.js
15+
RUN \[ "${DYNAMIC_CONFIG}" == "true" \] && sed -i 's/<!-- <script defer="defer" src=".\/config.js"><\/script> -->/<script defer="defer" src=".\/config.js"><\/script>/g' public/index.html
16+
RUN npm run build
17+
18+
19+
FROM nginx:1-alpine-slim
20+
21+
COPY --from=build-step /app/dist /usr/share/nginx/html
22+
COPY --from=build-step /app/config.schema.json /etc/nginx/conf.d/config.schema.json
23+
24+
# change default port to 8085
25+
RUN apk add jq pcre-tools && \
26+
sed -i 's/\s*listen\s*80;/ listen 8085;/' /etc/nginx/conf.d/default.conf && \
27+
sed -i 's/\s*location \/ {/ location \/ {\n try_files $uri $uri\/ \/index.html;/' /etc/nginx/conf.d/default.conf
28+
29+
EXPOSE 8085
30+
31+
STOPSIGNAL SIGTERM
32+
33+
# override entrypoint, which calls nginx-entrypoint underneath
34+
COPY --from=build-step /app/docker/docker-entrypoint.sh ./docker-entrypoint.d/40-stac-browser-entrypoint.sh

dockerfiles/browser_config.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module.exports = {
2+
catalogUrl: "http://0.0.0.0:8081",
3+
catalogTitle: "eoAPI STAC Browser",
4+
allowExternalAccess: true, // Must be true if catalogUrl is not given
5+
allowedDomains: [],
6+
detectLocaleFromBrowser: true,
7+
storeLocale: true,
8+
locale: "en",
9+
fallbackLocale: "en",
10+
supportedLocales: [
11+
"de",
12+
"es",
13+
"en",
14+
"fr",
15+
"it",
16+
"ro"
17+
],
18+
apiCatalogPriority: null,
19+
useTileLayerAsFallback: true,
20+
displayGeoTiffByDefault: false,
21+
buildTileUrlTemplate: ({href, asset}) => "http://0.0.0.0:8082/cog/tiles/{z}/{x}/{y}@2x?url=" + encodeURIComponent(asset.href.startsWith("/vsi") ? asset.href : href),
22+
stacProxyUrl: null,
23+
pathPrefix: "/",
24+
historyMode: "history",
25+
cardViewMode: "cards",
26+
cardViewSort: "asc",
27+
showThumbnailsAsAssets: false,
28+
stacLint: true,
29+
geoTiffResolution: 128,
30+
redirectLegacyUrls: false,
31+
itemsPerPage: 12,
32+
defaultThumbnailSize: null,
33+
maxPreviewsOnMap: 50,
34+
crossOriginMedia: null,
35+
requestHeaders: {},
36+
requestQueryParameters: {},
37+
preprocessSTAC: null,
38+
authConfig: null
39+
};

docs/src/customization.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,9 @@ By default, the API will look for tables in the `public` schema of the database.
6363
<img alt="eoapi.vector landing page" src="https://github.com/developmentseed/eoAPI/assets/10407788/b2a8a8d4-d3a1-464a-8b1a-166499ee4abd">
6464
</p>
6565

66-
Code: [/runtime/eoapi/vector](https://github.com/developmentseed/eoAPI/tree/main/runtime/eoapi/vector)
66+
Code: [/runtime/eoapi/vector](https://github.com/developmentseed/eoAPI/tree/main/runtime/eoapi/vector)
67+
68+
--
69+
# STAC browser
70+
71+
The custom browser configuration can be modified using the config located in [/dockerfiles/browser_config.js](https://github.com/developmentseed/eoAPI/tree/main/dockerfiles/browser_config.js). For more information about available configurations, see the [Radiant Earth repository](https://github.com/radiantearth/stac-browser).

docs/src/deployment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ hide:
77
## Via [eoapi-cdk](https://github.com/developmentseed/eoapi-cdk)
88

99

10-
[eoapi-cdk](https://github.com/developmentseed/eoapi-cdk) is a set of AWS CDK constructs to deploy eoAPI services.
10+
[eoapi-cdk](https://github.com/developmentseed/eoapi-cdk) is a set of AWS CDK constructs that can be used to easily deploy eoAPI services on AWS with the CDK.
1111

1212
[eoapi-template](https://github.com/developmentseed/eoapi-template) is an AWS CDK app that shows how to configure the [eoapi-cdk](https://github.com/developmentseed/eoapi-cdk) constructs.
1313

0 commit comments

Comments
 (0)