Skip to content

Commit 579ed47

Browse files
author
Phil Varner
authored
detect conformance classes correctly (#43)
1 parent 2875b46 commit 579ed47

File tree

2 files changed

+71
-49
lines changed

2 files changed

+71
-49
lines changed

COMPLIANCE_REPORT.md

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
This document shows how well several popular STAC API implementations conform to STAC API.
44

5-
Many (if not all) of these API are in production use, so the fact that they have validation problems
5+
Many (if not all) of these APIs are in production use, so the fact that they have validation problems
66
should not be seen as a significant concern. This validation suite is quite strict, so it finds
77
many obscure issues that can usually be worked around. Many of the defects are around the
88
correct advertisement of conformance classes and links to support hypermedia, and these more "advanced"
99
capabilities are only now starting to be fully used in tools like pystac-client.
1010

11-
## Open Source
11+
## Open Source Implementations
1212

1313
### stac-fastapi - sqlalchemy
1414

@@ -56,9 +56,31 @@ errors:
5656
- POST Search with {'ids': ['fe916452-ba6f-4631-9154-c249924a122d', 'f7f164c9-cfdf-436d-a3f0-69864c38ba2a']} returned items with ids other than specified one
5757
```
5858

59-
### stac-fastapi - Planetary Computer
59+
### stac-fastapi-elasticsearch
6060

61-
based on stac-fastapi
61+
TBD.
62+
63+
### Franklin
64+
65+
TBD.
66+
67+
### stac-server
68+
69+
TBD.
70+
71+
### resto
72+
73+
TBD.
74+
75+
### stac-cmr
76+
77+
### staccato
78+
79+
Non-compliant with 1.0.0-x
80+
81+
## Server Instances
82+
83+
### Microsoft Planetary Computer (stac-fastapi)
6284

6385
URL: https://planetarycomputer.microsoft.com/api/stac/v1/
6486

@@ -85,7 +107,26 @@ errors:
85107
- Search with datetime=37-01-01T12:00:27.87Z returned status code 500 instead of 400
86108
```
87109

88-
# stac-cmr
110+
111+
### Snap Planet (resto)
112+
113+
URL: https://tamn.snapplanet.io/
114+
115+
Date: 19-Jan-2022
116+
117+
Output
118+
```
119+
Validating https://tamn.snapplanet.io/
120+
STAC API - Core conformance class found.
121+
STAC API - Features conformance class found.
122+
STAC API - Item Search conformance class found.
123+
warnings:
124+
- Search with datetime=1985-04-12T23:20:50,52Z returned status code 200 instead of 400
125+
errors:
126+
- GET Search with {'limit': 10000} returned status code 400
127+
```
128+
129+
### EarthData CMR (stac-cmr)
89130

90131
URL: https://cmr.earthdata.nasa.gov/stac/USGS_EROS
91132

@@ -143,26 +184,8 @@ errors:
143184
- Search with datetime=2020-07-23T00:00:00.012345678Z returned status code 400
144185
```
145186

146-
# resto
147-
148-
URL: https://tamn.snapplanet.io/
149187

150-
Date: 19-Jan-2022
151-
152-
Output
153-
```
154-
Validating https://tamn.snapplanet.io/
155-
STAC API - Core conformance class found.
156-
STAC API - Features conformance class found.
157-
STAC API - Item Search conformance class found.
158-
warnings:
159-
- Search with datetime=1985-04-12T23:20:50,52Z returned status code 200 instead of 400
160-
errors:
161-
- GET Search with {'limit': 10000} returned status code 400
162-
```
163-
164-
165-
# Landsat Look
188+
### Landsat Look (stac-server)
166189

167190
URL: https://landsatlook.usgs.gov/stac-server
168191

@@ -228,7 +251,8 @@ errors:
228251
- Search with datetime=1990-12-31T23:59:61Z returned status code 404 instead of 400
229252
```
230253

231-
# Franklin
254+
255+
### Franklin NASA HSI
232256

233257
URL: https://franklin.nasa-hsi.azavea.com/
234258

@@ -273,7 +297,7 @@ errors:
273297
- Search with datetime=2020-07-23T00:00:00+03:00 returned status code 400
274298
```
275299

276-
# Staccato
300+
### staccato.space
277301

278302
URL: https://staccato.space/
279303

@@ -287,9 +311,8 @@ errors:
287311
- / : 'conformsTo' must contain at least one STAC API conformance class.
288312
```
289313

290-
## Proprietary
291314

292-
### Earth OnDemand
315+
### EarthAI OnDemand
293316

294317
URL: https://eod-catalog-svc-prod.astraea.earth/
295318

stac_api_validator/validations.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,25 @@
1212

1313
# resolve_stac_object
1414

15-
core_cc_regex = re.compile('https://api\.stacspec\.org/.+/core')
15+
core_cc_regex = re.compile(r'https://api\.stacspec\.org/.+/core')
1616

1717
oaf_cc_regex = re.compile(
18-
'https://api\.stacspec\.org/.+/ogcapi-features')
18+
r'https://api\.stacspec\.org/.+/ogcapi-features')
1919
oaf_transaction_cc_regex = re.compile(
20-
'https://api\.stacspec\.org/.+/ogcapi-features/extensions/transaction')
20+
r'https://api\.stacspec\.org/.+/ogcapi-features/extensions/transaction')
2121
oaf_version_cc_regex = re.compile(
22-
'https://api\.stacspec\.org/.+/ogcapi-features/extensions/version')
22+
r'https://api\.stacspec\.org/.+/ogcapi-features/extensions/version')
2323

24-
search_cc_regex = re.compile('https://api\.stacspec\.org/.+/item-search')
24+
search_cc_regex = re.compile(r'https://api\.stacspec\.org/.+/item-search')
2525
search_fields_cc_regex = re.compile(
26-
'https://api\.stacspec\.org/.+/item-search#fields')
26+
r'https://api\.stacspec\.org/.+/item-search#fields')
2727
search_contextsearch_fields_cc_regex_cc_regex = re.compile(
28-
'https://api\.stacspec\.org/.+/item-search#context')
28+
r'https://api\.stacspec\.org/.+/item-search#context')
2929
search_sort_cc_regex = re.compile(
30-
'https://api\.stacspec\.org/.+/item-search#sort')
30+
r'https://api\.stacspec\.org/.+/item-search#sort')
3131
search_query_cc_regex = re.compile(
32-
'https://api\.stacspec\.org/.+/item-search#query')
32+
r'https://api\.stacspec\.org/.+/item-search#query')
3333

34-
openapi_media_type = "application/vnd.oai.openapi+json;version=3.0"
3534
geojson_mt = 'application/geo+json'
3635
geojson_charset_mt = 'application/geo+json; charset=utf-8'
3736

@@ -115,9 +114,9 @@ def validate_api(root_url: str, post: bool) -> Tuple[List[str], List[str]]:
115114
errors.append("/ : 'links' field must be defined and non-empty.")
116115

117116
if conforms_to and \
118-
not any(core_cc_regex.match(x) for x in conforms_to) and \
119-
not any(oaf_cc_regex.match(x) for x in conforms_to) and \
120-
not any(search_cc_regex.match(x) for x in conforms_to):
117+
not any(core_cc_regex.fullmatch(x) for x in conforms_to) and \
118+
not any(oaf_cc_regex.fullmatch(x) for x in conforms_to) and \
119+
not any(search_cc_regex.fullmatch(x) for x in conforms_to):
121120
errors.append(
122121
"/ : 'conformsTo' must contain at least one STAC API conformance class.")
123122

@@ -130,18 +129,18 @@ def validate_api(root_url: str, post: bool) -> Tuple[List[str], List[str]]:
130129
if errors:
131130
return (warnings, errors)
132131

133-
if any(core_cc_regex.match(x) for x in conforms_to):
132+
if any(core_cc_regex.fullmatch(x) for x in conforms_to):
134133
print("STAC API - Core conformance class found.")
135134
validate_core(root_body, warnings, errors)
136135
else:
137136
errors.append(
138137
"/ : 'conformsTo' must contain STAC API - Core conformance class.")
139138

140-
if any(oaf_cc_regex.match(x) for x in conforms_to):
139+
if any(oaf_cc_regex.fullmatch(x) for x in conforms_to):
141140
print("STAC API - Features conformance class found.")
142141
validate_oaf(root_body, warnings, errors)
143142

144-
if any(search_cc_regex.match(x) for x in conforms_to):
143+
if any(search_cc_regex.fullmatch(x) for x in conforms_to):
145144
print("STAC API - Item Search conformance class found.")
146145
validate_search(root_body, post, conforms_to, warnings, errors)
147146

@@ -235,7 +234,7 @@ def validate_oaf(root_body: Dict, warnings: List[str],
235234
"conformance must return 200",
236235
lambda: r_conformance.status_code == 200)
237236

238-
if (ct := r_conformance.headers.get('content-type')) == 'application/json':
237+
if (ct := r_conformance.headers.get('content-type')).split(';')[0] == 'application/json':
239238
pass
240239
else:
241240
errors.append(
@@ -300,7 +299,7 @@ def validate_search(root_body: Dict, post: bool, conforms_to: List,
300299
errors.append(
301300
f"Search ({search_url}): must return JSON, instead got non-JSON text")
302301

303-
if any(search_fields_cc_regex.match(x) for x in conforms_to):
302+
if any(search_fields_cc_regex.fullmatch(x) for x in conforms_to):
304303
print("STAC API - Item Search Fields extension conformance class found.")
305304

306305
context = r.json().get("context")
@@ -604,16 +603,16 @@ def validate_search_ids(
604603
warnings: List[str],
605604
errors: List[str]
606605
):
607-
r = requests.get(f"{search_url}?limit=10")
606+
r = requests.get(f"{search_url}?limit=2")
608607
items = r.json().get("features")
609-
if items:
608+
if items and len(items) >= 2:
610609
_validate_search_ids_with_ids(search_url, [items[0].get("id")], post, errors)
611610
_validate_search_ids_with_ids(
612611
search_url, [items[0].get("id"), items[1].get("id")], post, errors)
613612
_validate_search_ids_with_ids(
614613
search_url, [i["id"] for i in items], post, errors)
615614
else:
616-
warnings.append(f"Get Search with no parameters returned zero results")
615+
warnings.append(f"Get Search with no parameters returned < 2 results")
617616

618617

619618
def _validate_search_collections_request(

0 commit comments

Comments
 (0)