Skip to content

Commit

Permalink
Merge pull request #10 from planetlabs/0.9.0
Browse files Browse the repository at this point in the history
WIP Upgrade to 0.9.0-RC1
  • Loading branch information
joshfix authored Apr 16, 2020
2 parents 8bfadfc + 706c58e commit 3813287
Show file tree
Hide file tree
Showing 123 changed files with 1,507 additions and 1,093 deletions.
3 changes: 0 additions & 3 deletions .idea/.gitignore

This file was deleted.

4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- STAC spec v0.9.0-RC1 updates

## [0.8.0.3] - 2019-10-30
## [0.9.0.0] - 2019-10-30
### Added
- STAC spec v0.8.0 updates
- Upgrade to Spring Boot 2.2.0
Expand Down
50 changes: 25 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Requires:

Example build command: `mvn clean install`

Additionally the docker image can be built from the [staccato-main](./staccato-main) package using the command:
Additionally the docker image can be built from the [staccato-application](./staccato-application) package using the command:
`mvn dockerfile:build`

### Running
Expand All @@ -50,15 +50,15 @@ An Elasticsearch instance must be available. To run locally in a docker contain
Any of the following methods are acceptable ways of running Staccato
- `./staccato-{version}.jar (self executing jar)`
- `java -jar staccato-{version}.jar`
- `mvn spring-boot:run` (from the [staccato-main](./staccato-main) directory)
- `mvn spring-boot:run` (from the [staccato-application](./staccato-application) directory)
- `docker run -d -i -t -p:8080:8080 quay.io/boundlessgeo/staccato:{version}`

## Endpoints

### API Endpoints

- GET /stac/search - dynamic catalog endpoint
- GET /stac/search/{id} - returns an item by ID
- GET /search - dynamic catalog endpoint
- GET /search/{id} - returns an item by ID

### Collection Endpoints

Expand All @@ -68,27 +68,27 @@ Any of the following methods are acceptable ways of running Staccato

### Catalog Endpoints

- GET /stac - retrieves the root catalog
- GET / - retrieves the root catalog
- GET /stac/{catalog_id} - retrieves a catalog by ID
- GET /stac/{catalog_id}/items - retrieves a collection of items belonging to a collection
- GET /stac/{collection_id}/items/{id} - retrieves an item by ID from a collection

### Transaction Endpoints

- POST /stac/{collection_id}/items - creates a new item
- PUT /stac/{collection_id}/items/{item_id} - creates a new item
- PATCH /stac/{collection_id}/items/{item_id} - updates an item item
- DELETE /stac/{collection_id}/items/{item_id} - deletes an item
- POST /collection/{collection_id}/items - creates a new item
- PUT /collection/{collection_id}/items/{item_id} - creates a new item
- PATCH /collection/{collection_id}/items/{item_id} - updates an item item
- DELETE /collection/{collection_id}/items/{item_id} - deletes an item

### Stats Endpoints

- GET /stac/stats - retrieves aggregations for all collections
- GET /stac/stats/{collection_id} - retrieves aggregations for a specific collection
- GET /stats - retrieves aggregations for all collections
- GET /stats/{collection_id} - retrieves aggregations for a specific collection

### Schema Endpoints

- GET /stac/schema - returns the STAC specification in JSON format
- GET /stac/schema/{collection_id} - returns the JSON schema for the specified collection
- GET /schema - returns the STAC specification in JSON format
- GET /schema/{collection_id} - returns the JSON schema for the specified collection

### Actuator Endpoints

Expand All @@ -103,15 +103,15 @@ Any of the following methods are acceptable ways of running Staccato
- **query** a Common Query Language text string to query properties of the catalog entry (see below for examples)
- **ids** a list of comma separated IDs to be returned
- **collections** a list of comma separated collection IDs on which to filter the results
- **fields.include** a comma separated list of json field names to include in the result
- **fields.exclude** a comma separated list of json field names to exclude in the result
- **fields** a comma separated list of json field names to include in the result; fields to be excluded can be prefixed with "-"
- **sortby** a comma separated list of fields to sort by

Examples:
_GET_
- <https://stac.boundlessgeo.io/stac/search?fields.include=id,bbox>
- [https://stac.boundlessgeo.io/stac/search?query=landsat:wrs_path=105 AND landsat:wrs_row=83](https://stac.boundlessgeo.io/stac/search?query=landsat:wrs_path=105%20AND%20landsat:wrs_row=83)
- <https://stac.boundlessgeo.io/stac/search?ids=LC81050832019135LGN00,LC81050822019135LGN00&collections=landsat-8-l1>
- [https://stac.boundlessgeo.io/stac/search?limit=20&page=2&query=eo:cloud_cover<0.1&bbox=27.3245,29.85465,30.5214,31.8685&time=2018-02-12T00:00:00Z/2019-06-12T00:00:00Z](https://stac.boundlessgeo.io/stac/search?limit=20&page=2&query=eo:cloud_cover%3C.1&bbox=27.3245,29.85465,30.5214,31.8685&time=2018-02-12T00:00:00Z/2019-06-12T00:00:00Z)
- <https://stac.boundlessgeo.io/search?fields.include=id,bbox>
- [https://stac.boundlessgeo.io/search?query=landsat:wrs_path=105 AND landsat:wrs_row=83](https://stac.boundlessgeo.io/stac/search?query=landsat:wrs_path=105%20AND%20landsat:wrs_row=83)
- <https://stac.boundlessgeo.io/search?ids=LC81050832019135LGN00,LC81050822019135LGN00&collections=landsat-8-l1>
- [https://stac.boundlessgeo.io/search?limit=20&page=2&query=eo:cloud_cover<0.1&bbox=27.3245,29.85465,30.5214,31.8685&time=2018-02-12T00:00:00Z/2019-06-12T00:00:00Z](https://stac.boundlessgeo.io/stac/search?limit=20&page=2&query=eo:cloud_cover%3C.1&bbox=27.3245,29.85465,30.5214,31.8685&time=2018-02-12T00:00:00Z/2019-06-12T00:00:00Z)

_POST_

Expand Down Expand Up @@ -163,7 +163,7 @@ _POST_
## Configuration

The STAC API has several properties that are configurable from the command line, as environment properties in the
[application.yml](./staccato-main/src/main/resources/application.yml) file. The table below details the properties that
[application.yml](./staccato-application/src/main/resources/application.yml) file. The table below details the properties that
are available for configuration.

Property | Default Value | Description
Expand Down Expand Up @@ -257,7 +257,7 @@ Each query interface defines a method to return the list of item types that the
the actual `doFilter` method which does the actual work. The basic premise is that the `doFilter` method accepts an
Item as input and returns an item as output. This can be used to automatically add data, remove data, or transform
data. Several examples of some included filters can be found in the
[filter](./staccato-main/src/main/java/com/planet/staccato/filter) package. Collections can also provide custom
[filter](./staccato-application/src/main/java/com/planet/staccato/filter) package. Collections can also provide custom
filters to accomplish various tasks, such as automatically generating links to related items based on values found in
the item's properties.

Expand Down Expand Up @@ -311,7 +311,7 @@ the `collection` field in every item. Because each collection will have a differ
implement several different extension interfaces or custom fieldsExtension, Jackson cannot deserialize Item classes without
more information on which properties class to deserialize to. Having the "collections" field in each item provides an
extremely convenient 1:1 relationship between the item and it's properties implementation. The Jackson configuration
for this can be found [here](./staccato-main/src/main/java/com/planet/staccato/config/ExtensionConfig.java).
for this can be found [here](./staccato-application/src/main/java/com/planet/staccato/config/ExtensionConfig.java).

### Custom annotations

Expand All @@ -326,7 +326,7 @@ Set type `type` attribute to one of the enumerated values found in

The `@Subcatalog` annotation, when applied to a `getter` interface method, will make that field eligible to be
automatically subcataloged via the `/stac/{catalog}` endpoint. The
[catalog spec implementation](./staccato-main/src/main/java/com/planet/staccato/catalog) will automatically detect
[catalog spec implementation](./staccato-application/src/main/java/com/planet/staccato/catalog) will automatically detect
methods with this annotation and build a subcatalog link containing the field name. That subcatalog will build links
containing all unique values in Elasticsearch for that field. After all eligible subcatalog fieldsExtension have been
traversed, the links section will be populated with links to all items that match the selected subcatalog values.
Expand Down Expand Up @@ -421,11 +421,11 @@ actual index it belongs to and update it on that index.

STAC will need to be configured with the mappings between the Elasticsearch alias name and the collection ID (eg, the
value used in the `items.properties.collection` field). This can be set in
[application.yml](./staccato-main/src/main/resources/application.yml) under the path
[application.yml](./staccato-application/src/main/resources/application.yml) under the path
`stac.es.index.aliases`. The key should be the name of the write alias used in Elasticsearch (not the actual index
name!). The value should be the collection id. So in our example case, the key would be `my-index-name` and the value
would be the collection ID. STAC will automatically append `-search` to the alias for executing searches.

At this point, you should be good to start inserting items. See the
[transaction API controller](./staccato-main/src/main/java/com/planet/staccato/transaction/TransactionApi.java)
[transaction API controller](./staccato-application/src/main/java/com/planet/staccato/transaction/TransactionApi.java)
for the proper methods to use for creating new items.
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@

<groupId>com.planet.staccato</groupId>
<artifactId>staccato</artifactId>
<version>0.8.0.3</version>
<version>0.9.0.1</version>
<packaging>pom</packaging>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<version>2.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<name>staccato</name>
<description>Staccato STAC implementation by Planet Labs</description>
<name>Staccato</name>
<description>STAC implementation by Planet Labs</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -33,7 +33,7 @@
</properties>

<modules>
<module>staccato-main</module>
<module>staccato-application</module>
<module>staccato-collections</module>
<module>staccato-commons</module>
<module>staccato-community</module>
Expand All @@ -45,7 +45,7 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RC1</version>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions staccato-main/pom.xml → staccato-application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
<modelVersion>4.0.0</modelVersion>

<groupId>com.planet.staccato</groupId>
<artifactId>staccato-main</artifactId>
<artifactId>staccato-application</artifactId>

<name>staccato-main</name>
<name>staccato-application</name>
<description>Planet STAC Implementation</description>

<parent>
<groupId>com.planet.staccato</groupId>
<artifactId>staccato</artifactId>
<version>0.8.0.3</version>
<version>0.9.0.1</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.planet.staccato;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.planet.staccato.config.StacConfigProps;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -40,6 +41,7 @@ public void run(ApplicationArguments args) throws Exception {
if (!configProps.isIncludeNullFields()) {
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

if (null != stacInitializers && !stacInitializers.isEmpty()) {
for (StacInitializer stacInitializer : stacInitializers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.Valid;

/**
* Defines the controller interface for the STAC API specification
* @see <a href="https://github.com/radiantearth/stac-spec/tree/master/api-spec">api-spec</a>
Expand All @@ -20,21 +22,21 @@ public interface ApiApi {
Mono<Item> getItem(@PathVariable("id") String id);

@GetMapping(path = "/search")
Mono<ItemCollection> getItems(SearchRequest searchRequest);
Mono<ItemCollection> getItems(@Valid SearchRequest searchRequest);

@GetMapping(path = "/search", produces = {MediaType.TEXT_EVENT_STREAM_VALUE,
MediaType.APPLICATION_STREAM_JSON_VALUE})
Flux<Item> getItemsStream(SearchRequest searchRequest);
Flux<Item> getItemsStream(@Valid SearchRequest searchRequest);

@PostMapping(value = "/search", consumes = MediaType.APPLICATION_JSON_VALUE)
Mono<ItemCollection> getItemsPost(@RequestBody SearchRequest searchRequest);
Mono<ItemCollection> getItemsPost(@Valid @RequestBody SearchRequest searchRequest);

@PostMapping(value = "/search", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = {MediaType.TEXT_EVENT_STREAM_VALUE, MediaType.APPLICATION_STREAM_JSON_VALUE})
Flux<Item> getItemsPostStream(@RequestBody SearchRequest searchRequest);
Flux<Item> getItemsPostStream(@Valid @RequestBody SearchRequest searchRequest);

@PostMapping(value = "/items", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE,
@PostMapping(value = "/search", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE}, produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
Mono<ItemCollection> getItemsFormPost(@ModelAttribute SearchRequest searchRequest);
Mono<ItemCollection> getItemsFormPost(@Valid @ModelAttribute SearchRequest searchRequest);

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.planet.staccato.api;

import com.planet.staccato.dto.api.SearchRequest;
import com.planet.staccato.dto.api.extensions.FieldsExtension;
import com.planet.staccato.dto.api.extensions.SortExtension;
import com.planet.staccato.model.Item;
import com.planet.staccato.model.ItemCollection;
import com.planet.staccato.service.ApiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


/**
* Defines the controller interface for the STAC API specification
* @see <a href="https://github.com/radiantearth/stac-spec/tree/master/api-spec">api-spec</a>
Expand All @@ -21,38 +24,54 @@
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/stac")
public class ApiController implements ApiApi {

private SortbyPropertyEditor sortbyPropertyEditor = new SortbyPropertyEditor();
private FieldsPropertyEditor fieldsPropertyEditor = new FieldsPropertyEditor();
private final ApiService service;

/**
* Registers a property editor to convert sortby parameter value for GET requests to SortbyExtension object.
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(SortExtension.class, "sortby", sortbyPropertyEditor);
binder.registerCustomEditor(FieldsExtension.class, "fields", fieldsPropertyEditor);
}

@Override
public Mono<Item> getItem(@PathVariable("id") String id) {
return service.getItem(id, null).name("getItem");
}

@Override
public Mono<ItemCollection> getItems(SearchRequest searchRequest) {
return service.getItems(searchRequest).name("getItems");
searchRequest.setMethod(HttpMethod.GET.toString());
return service.getItemCollection(searchRequest).name("getItems");
}

@Override
public Flux<Item> getItemsStream(SearchRequest searchRequest) {
searchRequest.setMethod(HttpMethod.GET.toString());
return service.getItemsFlux(searchRequest);
}

@Override
public Mono<ItemCollection> getItemsPost(@RequestBody SearchRequest searchRequest) {
return service.getItems(searchRequest).name("getItemsPost");
searchRequest.setMethod(HttpMethod.POST.toString());
return service.getItemCollection(searchRequest).name("getItemsPost");
}

@Override
public Flux<Item> getItemsPostStream(SearchRequest searchRequest) {
searchRequest.setMethod(HttpMethod.POST.toString());
return service.getItemsFlux(searchRequest);
}

@Override
public Mono<ItemCollection> getItemsFormPost(@ModelAttribute SearchRequest searchRequest) {
return service.getItems(searchRequest).name("getItemsFormPost");
searchRequest.setMethod(HttpMethod.POST.toString());
return service.getItemCollection(searchRequest).name("getItemsFormPost");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.planet.staccato.api;

import com.planet.staccato.dto.api.extensions.FieldsExtension;

import java.beans.PropertyEditorSupport;

/**
* The fields extension supports different formats depending on whether the request is GET or POST. The POST format
* uses the FieldsExtension object, whereas the GET format is simply an array of Strings and must be parsed. This
* property editor will convert the GET format to a FieldsExtension object so that the SearchRequest object only need
* to define the fields field as a FieldsExtension.
*
* @author joshfix
* Created on 1/15/20
*/
public class FieldsPropertyEditor extends PropertyEditorSupport {

@Override
public void setAsText(String text) {
if (text == null) {
return;
}

String[] fields = text.split(",");
FieldsExtension fieldsExtension = new FieldsExtension();
for (String field : fields) {

if (field.startsWith("-")) {
// if the field name starts with an dash, it is to be excluded
fieldsExtension.exclude(field.substring(1));
} else {
fieldsExtension.include(field);
}
}

setValue(fieldsExtension);
}
}
Loading

0 comments on commit 3813287

Please sign in to comment.