Skip to content

Commit 84e4ca7

Browse files
authored
Remove context extension by default (#871)
* default to node 22 * fix typos * remove context extension by default * remove context extension by default * fix bad merge
1 parent 9c514c5 commit 84e4ca7

File tree

8 files changed

+74
-34
lines changed

8 files changed

+74
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## unreleased - TBD
99

10-
## Removed
10+
### Removed
1111

12+
- Context Extension is not disabled by default, and can be enabled with ENABLE_CONTEXT_EXTENSION
1213
- Removed configurability of the Root / Landing Page Catalog stac_version via the
1314
STAC_VERSION environment variable. This is now fixed at 1.1.0.
1415
- Child link relations removed from root (landing page).

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- [Migration](#migration)
1111
- [Warnings](#warnings)
1212
- [4.0.0](#400)
13+
- [Context Extension disabled by default](#context-extension-disabled-by-default)
1314
- [Node 22 update](#node-22-update)
1415
- [3.10.0](#3100)
1516
- [Node 20 update](#node-20-update)
@@ -81,21 +82,22 @@ Stac-server is an implementation of the [STAC API specification](https://github.
8182
| 0.4.x | 1.0.0 | 1.0.0-beta.5 |
8283
| 0.5.x-0.8.x | 1.0.0 | 1.0.0-rc.2 |
8384
| >=1.0.0 | 1.0.0 | 1.0.0 |
85+
| >=3.10.0 | 1.1.0 | 1.0.0 |
8486

8587
Currently, stac-server supports the following specifications:
8688

8789
- STAC API - Core
8890
- STAC API - Features
8991
- STAC API - Collections
9092
- STAC API - Item Search
91-
- Context Extension (deprecated)
93+
- Context Extension (deprecated, disabled by default)
9294
- Sort Extension
9395
- Fields Extension
9496
- Query Extension
9597
- Filter Extension (conformance classes "Basic CQL2", "CQL2 JSON", "Basic Spatial Functions", and
9698
"Basic Spatial Functions with additional Spatial Literals", and
9799
the "in" and "between" predicates from "Advanced Comparison Operators")
98-
- Transaction Extension
100+
- Transaction Extension (disabled by default)
99101
- Aggregation Extension (experimental)
100102

101103
The following APIs are deployed instances of stac-server:
@@ -168,6 +170,12 @@ apiLambda --> opensearch
168170

169171
### 4.0.0
170172

173+
#### Context Extension disabled by default
174+
175+
Context Extension is not disabled by default, and can be enabled with ENABLE_CONTEXT_EXTENSION
176+
env var. Usage of the "context" object "limit", "matched", and "returned" fields can be replaced
177+
with the root-level fields "numberMatched" and "numberReturned".
178+
171179
#### Node 22 update
172180

173181
The default Lambda deployment environment is now Node 22.
@@ -566,6 +574,7 @@ There are some settings that should be reviewed and updated as needeed in the se
566574
| REQUEST_LOGGING_FORMAT | Express request logging format to use. Any of the [Morgan predefined formats](https://github.com/expressjs/morgan#predefined-formats). | tiny |
567575
| STAC_API_URL | The root endpoint of this API | Inferred from request |
568576
| ENABLE_TRANSACTIONS_EXTENSION | Boolean specifying if the [Transaction Extension](https://github.com/radiantearth/stac-api-spec/tree/master/ogcapi-features/extensions/transaction) should be activated | false |
577+
| ENABLE_CONTEXT_EXTENSION | Boolean specifying if the [Context Extension](https://github.com/stac-api-extensions/context) should be activated | false |
569578
| STAC_API_ROOTPATH | The path to append to URLs if this is not deployed at the server root. For example, if the server is deployed without a custom domain name, it will have the stage name (e.g., dev) in the path. | "" |
570579
| PRE_HOOK | The name of a Lambda function to be called as the pre-hook. | none |
571580
| POST_HOOK | The name of a Lambda function to be called as the post-hook. | none |

src/lib/api.js

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -479,17 +479,25 @@ export const addItemLinks = function (results, endpoint) {
479479
return results
480480
}
481481

482-
const wrapResponseInFeatureCollection = function (
483-
context, features = [], links = []
484-
) {
485-
return {
482+
const wrapResponseInFeatureCollection = function (features, links,
483+
numberMatched, numberReturned, limit) {
484+
const fc = {
486485
type: 'FeatureCollection',
487-
context,
488-
numberMatched: context.matched,
489-
numberReturned: context.returned,
486+
numberMatched,
487+
numberReturned,
490488
features,
491489
links
492490
}
491+
492+
if (process.env['ENABLE_CONTEXT_EXTENSION']) {
493+
fc['context'] = {
494+
matched: numberMatched,
495+
returned: numberReturned,
496+
limit
497+
}
498+
}
499+
500+
return fc
493501
}
494502

495503
const buildPaginationLinks = function (limit, parameters, bbox, intersects, endpoint,
@@ -572,7 +580,7 @@ const searchItems = async function (collectionId, queryParameters, backend, endp
572580
const fields = extractFields(queryParameters)
573581
const ids = extractIds(queryParameters)
574582
const collections = extractCollectionIds(queryParameters)
575-
const limit = extractLimit(queryParameters)
583+
const limit = extractLimit(queryParameters) || 10
576584
const page = extractPage(queryParameters)
577585

578586
const searchParams = pickBy({
@@ -599,16 +607,13 @@ const searchItems = async function (collectionId, queryParameters, backend, endp
599607

600608
let esResponse
601609
try {
602-
esResponse = await backend.search(searchParams, page, limit)
610+
esResponse = await backend.search(searchParams, limit, page)
603611
} catch (error) {
604612
if (isIndexNotFoundError(error)) {
605613
esResponse = {
606-
context: {
607-
matched: 0,
608-
returned: 0,
609-
limit
610-
},
611-
results: []
614+
results: [],
615+
numberMatched: 0,
616+
numberReturned: 0,
612617
}
613618
// @ts-ignore
614619
} else if (error?.meta?.statusCode === 400) {
@@ -631,7 +636,7 @@ const searchItems = async function (collectionId, queryParameters, backend, endp
631636
}
632637
}
633638

634-
const { results: responseItems, context } = esResponse
639+
const { results: responseItems, numberMatched, numberReturned } = esResponse
635640
const paginationLinks = buildPaginationLinks(
636641
limit, searchParams, bbox, intersects, newEndpoint, httpMethod, sortby, responseItems
637642
)
@@ -659,8 +664,7 @@ const searchItems = async function (collectionId, queryParameters, backend, endp
659664
}
660665

661666
const items = addItemLinks(responseItems, endpoint)
662-
const response = wrapResponseInFeatureCollection(context, items, links)
663-
return response
667+
return wrapResponseInFeatureCollection(items, links, numberMatched, numberReturned, limit)
664668
}
665669

666670
const agg = function (esAggs, name, dataType) {
@@ -1146,7 +1150,13 @@ const getCollections = async function (backend, endpoint = '') {
11461150
href: `${endpoint}`,
11471151
},
11481152
],
1149-
context: {
1153+
}
1154+
1155+
// note: adding this to the Collections response is not
1156+
// part of the Context Extension, and was just a proprietary
1157+
// behavior of this implemenation
1158+
if (process.env['ENABLE_CONTEXT_EXTENSION']) {
1159+
resp['context'] = {
11501160
page: 1,
11511161
limit: COLLECTION_LIMIT,
11521162
matched: linkedCollections && linkedCollections.length,
@@ -1183,7 +1193,7 @@ const createCollection = async function (collection, backend) {
11831193

11841194
const getItem = async function (collectionId, itemId, backend, endpoint = '') {
11851195
const itemQuery = { collections: [collectionId], id: itemId }
1186-
const { results } = await backend.search(itemQuery)
1196+
const { results } = await backend.search(itemQuery, 1)
11871197
const [it] = addItemLinks(results, endpoint)
11881198
if (it) {
11891199
return it
@@ -1233,7 +1243,7 @@ const deleteItem = async function (collectionId, itemId, backend) {
12331243

12341244
const getItemThumbnail = async function (collectionId, itemId, backend) {
12351245
const itemQuery = { collections: [collectionId], id: itemId }
1236-
const { results } = await backend.search(itemQuery)
1246+
const { results } = await backend.search(itemQuery, 1)
12371247
const [item] = results
12381248
if (!item) {
12391249
return new Error('Item not found')

src/lib/database.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ export async function constructSearchParams(parameters, page, limit) {
772772
return searchParams
773773
}
774774

775-
async function search(parameters, page, limit = 10) {
775+
async function search(parameters, limit, page) {
776776
const searchParams = await constructSearchParams(parameters, page, limit)
777777
const dbResponse = await dbQuery({
778778
ignore_unavailable: true,
@@ -783,12 +783,10 @@ async function search(parameters, page, limit = 10) {
783783
const results = dbResponse.body.hits.hits.map((r) => (r._source))
784784
const response = {
785785
results,
786-
context: {
787-
limit: Number(limit),
788-
matched: dbResponse.body.hits.total.value,
789-
returned: results.length
790-
}
786+
numberMatched: dbResponse.body.hits.total.value,
787+
numberReturned: results.length
791788
}
789+
792790
return response
793791
}
794792

@@ -977,7 +975,7 @@ const getItem = async (collectionId, itemId) => {
977975
const searchResponse = await search({
978976
collections: [collectionId],
979977
id: itemId
980-
})
978+
}, 1)
981979

982980
return searchResponse.results[0]
983981
}

src/lib/ingest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export async function convertIngestObjectToDbObject(
2828
index = data.collection
2929
} else {
3030
throw new InvalidIngestError(
31-
`Expected data.type to be "Collection" or "Feature" not ${data.type}`
31+
`Expected data.type to be 'Collection' or 'Feature' not '${data.type}'`
3232
)
3333
}
3434

tests/helpers/ingest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const ingestFixtureC = (ingestTopicArn, ingestQueueUrl) =>
7676

7777
export async function testPostIngestSNS(t, record, shouldError = false) {
7878
// @ts-ignore
79-
process.env.POST_INGEST_TOPIC_ARN = t.context.postIngestTopicArn
79+
process.env['POST_INGEST_TOPIC_ARN'] = t.context.postIngestTopicArn
8080

8181
await sns().publish({
8282
TopicArn: t.context.ingestTopicArn,

tests/system/test-api-get-collections.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test('GET /collections', async (t) => {
3434
t.true(Array.isArray(response.collections))
3535
t.true(response.collections.length > 0)
3636

37-
t.truthy(response.context.returned)
37+
t.falsy(response.context)
3838

3939
// queryables definition is stored in the collection document in OpenSearch,
4040
// but we do not want it in the Collection entity returned from the API or

tests/system/test-api-search-post.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,3 +1359,25 @@ test('/search - filter extension - s_intersects - non-existent geometry type', a
13591359
// eslint-disable-next-line max-len
13601360
/.*Operand for 's_intersects' must be a GeoJSON geometry: type was 'notPolygon'*/)
13611361
})
1362+
1363+
test('/search - context extension - no context when default', async (t) => {
1364+
const response = await t.context.api.client.post('search', { json: { } })
1365+
t.is(response.type, 'FeatureCollection')
1366+
t.is(response.numberMatched, 3)
1367+
t.is(response.numberReturned, 3)
1368+
1369+
t.falsy(response.context)
1370+
})
1371+
1372+
test('/search - context extension - context added when enabled', async (t) => {
1373+
process.env['ENABLE_CONTEXT_EXTENSION'] = 'true'
1374+
const response = await t.context.api.client.post('search', { json: { } })
1375+
t.is(response.type, 'FeatureCollection')
1376+
t.is(response.numberMatched, 3)
1377+
t.is(response.numberReturned, 3)
1378+
1379+
t.truthy(response.context)
1380+
t.is(response.context.matched, 3)
1381+
t.is(response.context.returned, 3)
1382+
t.is(response.context.limit, 10)
1383+
})

0 commit comments

Comments
 (0)