Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part4 update #153

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* [OGC API for Features version 1.0](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html)
* [OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)](https://portal.ogc.org/files/96288)
* [OpenAPI Specifcation version 3.0.2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md)
* [OGC API - Features - Part 4: Create, Replace, Update and Delete](https://docs.ogc.org/DRAFTS/20-002.html)

## Notes

Expand Down Expand Up @@ -63,10 +64,12 @@ JSON document containing feature collection metadata.
* items - `/collections/{cid}/items.html` - Features as HTML

## Features
Access to features in a collection.

### GET
Produces a dataset of items from the collection (as GeoJSON)

### Request
#### Request
Path: `/collections/{cid}/items`

### Parameters
Expand All @@ -88,7 +91,7 @@ Usually used with an aggregate `transform` function.
* `limit=N` - limits the number of features in the response.
* `offset=N` - starts the response at an offset.

### Response
#### Response

GeoJSON document containing the features resulting from the request query.

Expand All @@ -99,22 +102,63 @@ GeoJSON document containing the features resulting from the request query.
* next - TBD
* prev - TBD

### POST
Create a feature in collection.

#### Request
Path: `/collections/{cid}/items`
Content: JSON document representing a geojson feature.

#### Response
Empty response with 201 HTTP Status Code.

## Feature
Provides access to one collection feature.

### Request
### GET
Get one collection feature.

#### Request
Path: `/collections/{cid}/items/{fid}`

#### Parameters
##### Parameters
* `properties=PROP-LIST`- return only the given properties (comma-separated)
* `transform` - transform the feature geometry by the given geometry function pipeline

### Response
#### Response

#### Links
##### Links
* self - `/collections/{cid}/items/{fid}.json` - This document as JSON
* alternate - `/collections/{cid}/items/{fid}.html` - This document as HTML
* collection - `/collections/{cid}` - The collection document

### PUT
Replace one collection feature.
#### Request
Path: `/collections/{cid}/items/{fid}`
Content: JSON document representing a geojson feature.

#### Response
Empty response with 200 HTTP Status Code.

### PATCH
Update one collection feature.
#### Request
Path: `/collections/{cid}/items/{fid}`
Content: JSON document representing a geojson feature.

#### Response
Empty response with 200 HTTP Status Code.

### DELETE
Delete one collection feature.

#### Request
Path: `/collections/{cid}/items/{fid}`

#### Response
Empty response with 200 HTTP Status Code.

## Functions

Lists the functions provided by the service.
Expand Down
8 changes: 7 additions & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,19 @@ It includes [*OGC API - Features*](http://docs.opengeospatial.org/is/17-069r3/17

### Output formats
- [x] GeoJSON
- [ ] GML
- [x] JSON for metadata
- [x] JSON for non-geometry functions
- [ ] `next` link
- [ ] `prev` link

### Input formats
- [x] GeoJSON
- [ ] GML

### Transactions
- [ ] Support POST, PUT, PATCH, DELETE... TBD
- [X] Support POST, PUT, PATCH, DELETE on tables with primary key
- [ ] Support Optimistic locking

## User Interface (HTML)
- [x] `/home.html` landing page
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ See also our companion project [`pg_tileserv`](https://github.com/CrunchyData/pg
* Standard query parameters: `limit`, `bbox`, `bbox-crs`, property filtering, `sortby`, `crs`
* Query parameters `filter` and `filter-crs` allow [CQL filtering](https://portal.ogc.org/files/96288), with spatial support
* Extended query parameters: `offset`, `properties`, `transform`, `precision`, `groupby`
* Transactions (Create, Update, Replace, Delete)
* Data responses are formatted in JSON and [GeoJSON](https://www.rfc-editor.org/rfc/rfc7946.txt)
* Request content for transactions supports [GeoJSON](https://www.rfc-editor.org/rfc/rfc7946.txt)
* Provides a simple HTML user interface, with web maps to view spatial data
* Uses the power of PostgreSQL to reduce the amount of code
and to make data definition easy and familiar.
Expand Down Expand Up @@ -46,6 +48,8 @@ For a full list of software capabilities see [FEATURES](FEATURES.md).
* [*OGC API - Features - Part 2: Coordinate Reference Systems by Reference*](https://docs.ogc.org/is/18-058/18-058.html)
* [**DRAFT** *OGC API - Features - Part 3: Filtering*](http://docs.ogc.org/DRAFTS/19-079r1.html)
* [**DRAFT** *Common Query Language (CQL2)*](https://docs.ogc.org/DRAFTS/21-065.html)
* [**DRAFT** *OGC API - Features - Part 4: Create, Replace, Update and Delete*](https://docs.ogc.org/DRAFTS/20-002.html)

* [*GeoJSON*](https://www.rfc-editor.org/rfc/rfc7946.txt)

## Download
Expand Down
1 change: 1 addition & 0 deletions hugo/content/usage/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ This section describes how to use `pg_featureserv`. It covers the following topi
* How the [Web Service API](./api/) works
* How to publish [feature collections](./collections/) backed by PostGIS tables or views
* How to [query features](./query_data/) from feature collections
* How to [create update replace delete feature](./create_update_replace_delete_feature/) in feature collections
* How to publish database [functions](./functions/)
* How to [execute functions](./query_function/)
63 changes: 63 additions & 0 deletions hugo/content/usage/create_update_replace_delete_feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: "Create Replace Delete Feature"
date:
draft: false
weight: 150
---

Transaction on Feature collections is supported.

## Create feature

POST query to the path `/collections/{collid}/items` allows to create
a new feature in a feature collection.

The geojson feature must be part of the request body.
If the geometry geometry crs is different from the storage crs, the geometry will be transformed.
Missing properties will be ignored and the table default value for the column will be applied.
The id specified in the body is ignored and the database default value is used to create the feature.

#### Example
```
curl -i --request "POST" 'http://localhost:9000/collections/public.tramway_stations/items' -d '{"type":"Feature","id":"129","geometry":{"type":"Point","coordinates":[-71.222868058,46.836016945,0]},"properties":{"description":null,"diffusion":"Publique","niveau_rstc":"Tramway","nom":"Hôpital Enfant-Jésus","objectid":129,"type_station":"Reguliere"}}'
```
## Update feature

PATCH query to the path `/collections/{collid}/items/{fid}` allows to update
a feature in a feature collection.

The geojson feature must be part of the request body.
If the geometry geometry crs is different from the storage crs, the geometry will be transformed.
Missing properties will not be updated.
The id specified in the body is ignored.

#### Example
```
curl -i --request "PUT" 'http://localhost:9000/collections/public.tramway_stations/items/129.json' -d '{"type":"Feature","id":"129","geometry":{"type":"Point","coordinates":[-71.222868058,46.836016945,0]},"properties":{"description":null,"diffusion":"Publique","niveau_rstc":"Tramway","nom":"Hôpital Enfant-Jésus","objectid":129,"type_station":"Reguliere"}}'
```

## Replace feature

PUT query to the path `/collections/{collid}/items/{fid}` allows to replace
a feature in a feature collection.

The geojson feature must be part of the request body.
If the geometry geometry crs is different from the storage crs, the geometry will be transformed.
Missing properties will be replaced with null (unless a database trigger is applied)
The id specified in the body is ignored.

#### Example
```
curl -i --request "PUT" 'http://localhost:9000/collections/public.tramway_stations/items/129.json' -d '{"type":"Feature","id":"129","geometry":{"type":"Point","coordinates":[-71.222868058,46.836016945,0]},"properties":{"description":null,"diffusion":"Publique","niveau_rstc":"Tramway","nom":"Hôpital Enfant-Jésus","objectid":129,"type_station":"Reguliere"}}'
```

## Delete feature

DELETE query to the path `/collections/{collid}/items/{fid}` allows to delete
a feature in a feature collection.

#### Example
```
curl -i --request "Delete" 'http://localhost:9000/collections/public.tramway_stations/items/129.json'
```

3 changes: 3 additions & 0 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,9 @@ var conformance = Conformance{
"http://www.opengis.net/spec/ogcapi-common-1/1.0/conf/oas30",
"http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/collections",
"http://www.opengis.net/spec/ogcapi-common-2/1.0/conf/simple-query",
"http://www.opengis.net/spec/ogcapi-features-4/1.0/conf/create-replace-delete",
"http://www.opengis.net/spec/ogcapi-features-4/1.0/conf/update",
"http://www.opengis.net/spec/ogcapi-features-4/1.0/conf/features",
Comment on lines +485 to +487
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the linked location/website does not exist. is this intended?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are the conformance class url from the specification: https://docs.ogc.org/DRAFTS/20-002.html#_conformance

},
}

Expand Down
124 changes: 122 additions & 2 deletions internal/api/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,36 @@ func GetOpenAPIContent(urlBase string) *openapi3.Swagger {
},
},
},
Post: &openapi3.Operation{
OperationID: "createCollectionFeature",
Parameters: openapi3.Parameters{
&paramCollectionID,
},
RequestBody: &openapi3.RequestBodyRef{
Value: &openapi3.RequestBody{
Description: "Feature",
Required: true,
/*
// TODO: create schema for input?
Content: openapi3.NewContentWithJSONSchemaRef(
&openapi3.SchemaRef{
Ref: "http://geojson.org/schema/Feature.json",
},
),
*/
},
},
Responses: openapi3.Responses{
"201": &openapi3.ResponseRef{
Value: &openapi3.Response{
Description: "Created"},
},
},
},
},
apiBase + "collections/{collectionId}/items/{featureId}": &openapi3.PathItem{
Summary: "Single feature data from collection",
Description: "Provides access to a single feature identitfied by {featureId} from the specified collection",
Summary: "Feature in collection",
Description: "Gets, Replaces or Deletes Single Feature in collection.",
Get: &openapi3.Operation{
OperationID: "getCollectionFeature",
Parameters: openapi3.Parameters{
Expand Down Expand Up @@ -393,6 +419,100 @@ func GetOpenAPIContent(urlBase string) *openapi3.Swagger {
},
},
},
Patch: &openapi3.Operation{
OperationID: "updateCollectionFeature",
Parameters: openapi3.Parameters{
&paramCollectionID,
&openapi3.ParameterRef{
Value: &openapi3.Parameter{
Name: "featureId",
Description: "ID of feature in collection to update.",
In: "path",
Required: true,
Schema: &openapi3.SchemaRef{Value: openapi3.NewStringSchema()},
AllowEmptyValue: false,
},
},
},
RequestBody: &openapi3.RequestBodyRef{
Value: &openapi3.RequestBody{
Description: "Feature",
Required: true,
/*
// TODO: create schema for input?
Content: openapi3.NewContentWithJSONSchemaRef(
&openapi3.SchemaRef{
Ref: "http://geojson.org/schema/Feature.json",
},
),
*/
},
},
Responses: openapi3.Responses{
"204": &openapi3.ResponseRef{
Value: &openapi3.Response{
Description: "No Content"},
},
},
},
Put: &openapi3.Operation{
OperationID: "replaceCollectionFeature",
Parameters: openapi3.Parameters{
&paramCollectionID,
&openapi3.ParameterRef{
Value: &openapi3.Parameter{
Name: "featureId",
Description: "ID of feature in collection to replace.",
In: "path",
Required: true,
Schema: &openapi3.SchemaRef{Value: openapi3.NewStringSchema()},
AllowEmptyValue: false,
},
},
},
RequestBody: &openapi3.RequestBodyRef{
Value: &openapi3.RequestBody{
Description: "Feature",
Required: true,
/*
// TODO: create schema for input?
Content: openapi3.NewContentWithJSONSchemaRef(
&openapi3.SchemaRef{
Ref: "http://geojson.org/schema/Feature.json",
},
),
*/
},
},
Responses: openapi3.Responses{
"204": &openapi3.ResponseRef{
Value: &openapi3.Response{
Description: "No Content"},
},
},
},
Delete: &openapi3.Operation{
OperationID: "deleteCollectionFeature",
Parameters: openapi3.Parameters{
&paramCollectionID,
&openapi3.ParameterRef{
Value: &openapi3.Parameter{
Name: "featureId",
Description: "ID of feature in collection to delete.",
In: "path",
Required: true,
Schema: &openapi3.SchemaRef{Value: openapi3.NewStringSchema()},
AllowEmptyValue: false,
},
},
},
Responses: openapi3.Responses{
"204": &openapi3.ResponseRef{
Value: &openapi3.Response{
Description: "No Content"},
},
},
},
},
apiBase + "functions": &openapi3.PathItem{
Summary: "Functions metadata",
Expand Down
26 changes: 26 additions & 0 deletions internal/data/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ type Catalog interface {
// It returns an empty string if the table or feature does not exist
TableFeature(ctx context.Context, name string, id string, param *QueryParam) (string, error)

// ReplaceTableFeature replaces a feature
ReplaceTableFeature(ctx context.Context, name string, id string, feature Feature) error

// UpdateTableFeature updates a feature
UpdateTableFeature(ctx context.Context, name string, id string, feature Feature) error

// CreateTableFeature creates a feature
CreateTableFeature(ctx context.Context, name string, feature Feature) error

// DeleteTableFeature deletes a feature
DeleteTableFeature(ctx context.Context, name string, id string) error

Functions() ([]*Function, error)

// FunctionByName returns the function with given name.
Expand Down Expand Up @@ -163,3 +175,17 @@ func FunctionQualifiedId(name string) string {
}
return SchemaPostGISFTW + "." + name
}

type Geometry struct {
Type string `json:"type"`
Coordinates interface{} `json:"coordinates"`
CRS map[string]interface{} `json:"crs,omitempty"`
}

// A Feature corresponds to GeoJSON feature object
type Feature struct {
ID interface{} `json:"id,omitempty"`
Type string `json:"type"`
Geometry *Geometry `json:"geometry"`
Properties map[string]interface{} `json:"properties"`
}
Loading
Loading