Skip to content

Commit 070c581

Browse files
author
Phil Varner
authored
Merge pull request #342 from stac-utils/backport/thumbnail-endpoint
v.0.4.2 backport: add support for thumbnail endpoint
2 parents 65b2ec6 + 32d663e commit 070c581

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [0.4.2] - 2022-12-20
9+
10+
### Added
11+
12+
- (Experimental) Adds Item 'thumbnail' link to presign an s3 protocol thumbnail asset ARN
13+
814
## [0.4.1] - 2022-07-11
915

1016
### Added
@@ -151,6 +157,7 @@ Initial release, forked from [sat-api](https://github.com/sat-utils/sat-api/tree
151157

152158
Compliant with STAC 0.9.0
153159

160+
[0.4.2]: https://github.com/stac-utils/stac-api/compare/v0.4.2...v0.4.2
154161
[0.4.1]: https://github.com/stac-utils/stac-api/compare/v0.4.0...v0.4.1
155162
[0.4.0]: https://github.com/stac-utils/stac-api/compare/v0.3.1...v0.4.0
156163
[0.3.1]: https://github.com/stac-utils/stac-api/compare/v0.3.0...v0.3.1

src/lambdas/api/app.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,31 @@ app.delete('/collections/:collectionId/items/:itemId', async (req, res, next) =>
268268
}
269269
})
270270

271+
app.get('/collections/:collectionId/items/:itemId/thumbnail', async (req, res, next) => {
272+
try {
273+
const { itemId, collectionId } = req.params
274+
275+
const response = await api.getItemThumbnail(
276+
collectionId,
277+
itemId,
278+
es,
279+
)
280+
281+
if (response instanceof Error) {
282+
if (response.message === 'Item not found'
283+
|| response.message === 'Thumbnail not found') {
284+
next(createError(404))
285+
} else {
286+
next(createError(500))
287+
}
288+
} else {
289+
res.redirect(response.location)
290+
}
291+
} catch (error) {
292+
next(error)
293+
}
294+
})
295+
271296
// catch 404 and forward to error handler
272297
app.use((_req, _res, next) => {
273298
next(createError(404))

src/lib/api.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { pickBy, assign, get: getNested } = require('lodash')
22
const extent = require('@mapbox/extent')
33
const { DateTime } = require('luxon')
4+
const AWS = require('aws-sdk')
45
const { isIndexNotFoundError } = require('./es')
56
const logger = console
67

@@ -357,6 +358,10 @@ const addItemLinks = function (results, endpoint) {
357358
rel: 'root',
358359
href: `${endpoint}/`
359360
})
361+
links.push({
362+
rel: 'thumbnail',
363+
href: `${endpoint}/collections/${collection}/items/${id}/thumbnail`
364+
})
360365
result.type = 'Feature'
361366
return result
362367
})
@@ -689,6 +694,41 @@ const deleteItem = async function (collectionId, itemId, backend) {
689694
return new Error(`Error deleting item ${collectionId}/${itemId}`)
690695
}
691696

697+
const getItemThumbnail = async function (collectionId, itemId, backend) {
698+
const itemQuery = { collections: [collectionId], id: itemId }
699+
const { results } = await backend.search(itemQuery)
700+
const [item] = results
701+
if (!item) {
702+
return new Error('Item not found')
703+
}
704+
705+
const thumbnailAsset = Object.values(item.assets || []).find(
706+
(x) => x.roles && x.roles.includes('thumbnail')
707+
)
708+
if (!thumbnailAsset) {
709+
return new Error('Thumbnail not found')
710+
}
711+
712+
let location
713+
if (thumbnailAsset.href && thumbnailAsset.href.startsWith('http')) {
714+
location = thumbnailAsset.href
715+
} else if (thumbnailAsset.href && thumbnailAsset.href.startsWith('s3')) {
716+
const withoutProtocol = thumbnailAsset.href.substring(5) // chop off s3://
717+
const [bucket, ...keyArray] = withoutProtocol.split('/')
718+
const key = keyArray.join('/')
719+
location = new AWS.S3().getSignedUrl('getObject', {
720+
Bucket: bucket,
721+
Key: key,
722+
Expires: 60 * 5, // expiry in seconds
723+
RequestPayer: 'requester'
724+
})
725+
} else {
726+
return new Error('Thumbnail not found')
727+
}
728+
729+
return { location }
730+
}
731+
692732
module.exports = {
693733
getConformance,
694734
getCatalog,
@@ -705,5 +745,6 @@ module.exports = {
705745
partialUpdateItem,
706746
ValidationError,
707747
extractLimit,
708-
extractDatetime
748+
extractDatetime,
749+
getItemThumbnail,
709750
}

0 commit comments

Comments
 (0)