diff --git a/.gitignore b/.gitignore
index 7cd99ce..97d8eef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,3 +114,5 @@ ENV/
*.code-workspace
.DS_Store
+
+pygeoapi/django_pygeoapi/sample_project/db.sqlite3
diff --git a/docs/source/downstream.rst b/docs/source/downstream.rst
new file mode 100644
index 0000000..1957351
--- /dev/null
+++ b/docs/source/downstream.rst
@@ -0,0 +1,103 @@
+.. _downstream:
+
+Downstream Projects
+=======
+
+Downstreaming `pygeoapi` project with various python frameworks.
+
+------------------
+
+In this page, we'll demonstrate how to downstream `pygeoapi` project with various python frameworks.
+
+
+Django
+^^^^^^
+
+Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Click `here `_ to read more about Django.
+
+In this section we create a sample django project and use `pygeoapi` package as a pluggable django application and serve all the capabilities of `pygeoapi` using Django. For the truly impatient developers, there is a Django `sample_project` in the source code.
+
+To create everything from scratch please follow these steps :
+
+- Create a Project folder and create a fresh virtual environment using your preferred tool. e.g.
+
+.. code-block:: bash
+
+ python3 -m venv env
+
+Once created, activate it.
+
+- Install the following dependencies
+
+.. code-block:: bash
+
+ pip install Django pygeoapi
+
+- Create a django project in a directory and cd into it.
+
+.. code-block:: python
+
+ django-admin startproject sampleproject
+ cd /sampleproject
+
+- Download `pygeoapi-config.yml` using
+
+.. code-block:: bash
+
+ curl -O https://raw.githubusercontent.com/geopython/pygeoapi/django_pygeoapi/sample_project/pygeoapi-config.yml
+
+and put it in the same folder at root level.
+
+- Set environment variable
+
+.. code-block:: bash
+
+ export PYGEOAPI_CONFIG=pygeoapi-config.yml
+ export PYGEOAPI_OPENAPI=example-openapi.yml
+
+- Run `python manage.py collectstatic` to get all static files.
+- Generate OpenAPI document using following `pygeoapi` command
+
+.. code-block:: bash
+
+ pygeoapi openapi generate $PYGEOAPI_CONFIG --output-file $PYGEOAPI_OPENAPI
+
+- Update Django `sampleproject/settings.py` file as per following
+
+.. code-block:: python
+
+ import os
+ from pygeoapi.django_app import config
+
+ INSTALLED_APPS = [
+ # other apps
+ ....
+ #pygeoapi app
+ 'pygeoapi'
+ ]
+
+ # Put following setting after STATIC_URL
+ STATIC_ROOT = os.path.join( BASE_DIR / 'assets')
+
+ # Specific pygeoapi setting
+ PYGEOAPI_CONFIG = config()
+ ...
+
+- Update Django `sampleproject/urls.py` file to run pygeoapi at e.g. `pga` path
+
+.. code-block:: python
+
+ from django.contrib import admin
+ from django.urls import path, include
+ from pygeoapi.django_pygeoapi import urls
+ urlpatterns = [
+ path('admin/', admin.site.urls),
+ path('pga/', include(urls)) # added here
+ ]
+
+- Update pygeoapi `pygeoapi-config.yml` file with following settings
+
+1. Update the `url` property under `server` in `pygeoapi-config.yml` accordingly to your django project url. e.g. In this case the path set is `pga` .
+2. Update all data paths e.g. `tests/data/ne_110m_lakes.geojson` to match with the absolute path of the pygeoapi project directory.
+
+- Run Django project using `python manage.py runserver`. Once server starts, head over to `localhost:8000/pga` to see `pygeoapi` running.
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6194b36..0651f15 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -23,6 +23,7 @@ pygeoapi |release| documentation
configuration
administration
running
+ downstream
running-with-docker
tour
openapi
diff --git a/pygeoapi-openapi.yml b/pygeoapi-openapi.yml
new file mode 100644
index 0000000..e00b19d
--- /dev/null
+++ b/pygeoapi-openapi.yml
@@ -0,0 +1,880 @@
+components:
+ parameters:
+ f:
+ description: The optional f parameter indicates the output format which the
+ server shall provide as part of the response document. The default format
+ is GeoJSON.
+ explode: false
+ in: query
+ name: f
+ required: false
+ schema:
+ default: json
+ enum:
+ - json
+ - html
+ - jsonld
+ type: string
+ style: form
+ lang:
+ description: The optional lang parameter instructs the server return a response
+ in a certain language, if supported. If the language is not among the available
+ values, the Accept-Language header language will be used if it is supported.
+ If the header is missing, the default server language is used. Note that providers
+ may only support a single language (or often no language at all), that can
+ be different from the server language. Language strings can be written in
+ a complex (e.g. "fr-CA,fr;q=0.9,en-US;q=0.8,en;q=0.7"), simple (e.g. "de")
+ or locale-like (e.g. "de-CH" or "fr_BE") fashion.
+ in: query
+ name: lang
+ required: false
+ schema:
+ default: en-US
+ enum:
+ - en-US
+ - fr-CA
+ type: string
+ properties:
+ description: The properties that should be included for each feature. The parameter
+ value is a comma-separated list of property names.
+ explode: false
+ in: query
+ name: properties
+ required: false
+ schema:
+ items:
+ type: string
+ type: array
+ style: form
+ skipGeometry:
+ description: This option can be used to skip response geometries for each feature.
+ explode: false
+ in: query
+ name: skipGeometry
+ required: false
+ schema:
+ default: false
+ type: boolean
+ style: form
+ startindex:
+ description: The optional startindex parameter indicates the index within the
+ result set from which the server shall begin presenting results in the response
+ document. The first element has an index of 0 (default).
+ explode: false
+ in: query
+ name: startindex
+ required: false
+ schema:
+ default: 0
+ minimum: 0
+ type: integer
+ style: form
+ responses:
+ '200':
+ description: successful operation
+ Queryables:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/queryables'
+ description: successful queryables operation
+ default:
+ content:
+ application/json:
+ schema:
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/schemas/exception.yaml
+ description: Unexpected error
+ schemas:
+ queryable:
+ properties:
+ description:
+ description: a human-readable narrative describing the queryable
+ type: string
+ language:
+ default:
+ - en
+ description: the language used for the title and description
+ type: string
+ queryable:
+ description: the token that may be used in a CQL predicate
+ type: string
+ title:
+ description: a human readable title for the queryable
+ type: string
+ type:
+ description: the data type of the queryable
+ type: string
+ type-ref:
+ description: a reference to the formal definition of the type
+ format: url
+ type: string
+ required:
+ - queryable
+ - type
+ type: object
+ queryables:
+ properties:
+ queryables:
+ items:
+ $ref: '#/components/schemas/queryable'
+ type: array
+ required:
+ - queryables
+ type: object
+info:
+ contact:
+ email: you@example.org
+ name: Organization Name
+ url: https://pygeoapi.io
+ description: pygeoapi provides an API to geospatial data
+ license:
+ name: CC-BY 4.0 license
+ url: https://creativecommons.org/licenses/by/4.0/
+ termsOfService: https://creativecommons.org/licenses/by/4.0/
+ title: pygeoapi default instance
+ version: 0.13.dev0
+ x-keywords:
+ - geospatial
+ - data
+ - api
+openapi: 3.0.2
+paths:
+ /:
+ get:
+ description: Landing page
+ operationId: getLandingPage
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/LandingPage
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Landing page
+ tags:
+ - server
+ /collections:
+ get:
+ description: Collections
+ operationId: getCollections
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collections
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Collections
+ tags:
+ - server
+ /collections/canada-metadata:
+ get:
+ description: Sample metadata records from open.canada.ca
+ operationId: describeCanada-metadataCollection
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Open Canada sample data metadata
+ tags:
+ - canada-metadata
+ /collections/canada-metadata/items:
+ get:
+ description: Sample metadata records from open.canada.ca
+ operationId: getCanada-metadataFeatures
+ parameters:
+ - &id001
+ description: The optional f parameter indicates the output format which the
+ server shall provide as part of the response document. The default format
+ is GeoJSON.
+ explode: false
+ in: query
+ name: f
+ required: false
+ schema:
+ default: json
+ enum:
+ - json
+ - html
+ - jsonld
+ - csv
+ type: string
+ style: form
+ - &id002
+ description: The optional lang parameter instructs the server return a response
+ in a certain language, if supported. If the language is not among the available
+ values, the Accept-Language header language will be used if it is supported.
+ If the header is missing, the default server language is used. Note that
+ providers may only support a single language (or often no language at all),
+ that can be different from the server language. Language strings can be
+ written in a complex (e.g. "fr-CA,fr;q=0.9,en-US;q=0.8,en;q=0.7"), simple
+ (e.g. "de") or locale-like (e.g. "de-CH" or "fr_BE") fashion.
+ in: query
+ name: lang
+ required: false
+ schema:
+ default: en-US
+ enum:
+ - en-US
+ - fr-CA
+ type: string
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/limit
+ - description: The properties that should be included for each feature. The
+ parameter value is a comma-separated list of property names.
+ explode: false
+ in: query
+ name: properties
+ required: false
+ schema:
+ items:
+ enum:
+ - recordCreated
+ - recordUpdated
+ - type
+ - title
+ - description
+ - contactPoint
+ - associations
+ - externalId
+ - themes
+ - q
+ type: string
+ type: array
+ style: form
+ - $ref: '#/components/parameters/skipGeometry'
+ - $ref: https://raw.githubusercontent.com/opengeospatial/ogcapi-records/master/core/openapi/parameters/sortby.yaml
+ - $ref: '#/components/parameters/startindex'
+ - $ref: https://raw.githubusercontent.com/opengeospatial/ogcapi-records/master/core/openapi/parameters/q.yaml
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/datetime
+ - explode: false
+ in: query
+ name: recordCreated
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: recordUpdated
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: type
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: title
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: description
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: contactPoint
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: associations
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: externalId
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: themes
+ required: false
+ schema:
+ type: string
+ style: form
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Open Canada sample data items
+ tags:
+ - canada-metadata
+ /collections/canada-metadata/items/{featureId}:
+ get:
+ description: Sample metadata records from open.canada.ca
+ operationId: getCanada-metadataFeature
+ parameters:
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Open Canada sample data item by id
+ tags:
+ - canada-metadata
+ /collections/canada-metadata/queryables:
+ get:
+ description: Sample metadata records from open.canada.ca
+ operationId: getCanada-metadataQueryables
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: '#/components/responses/Queryables'
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Open Canada sample data queryables
+ tags:
+ - canada-metadata
+ /collections/gdps-temperature:
+ get:
+ description: Global Deterministic Prediction System sample
+ operationId: describeGdps-temperatureCollection
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Global Deterministic Prediction System sample metadata
+ tags:
+ - gdps-temperature
+ /collections/gdps-temperature/coverage:
+ get:
+ description: Global Deterministic Prediction System sample
+ operationId: getGdps-temperatureCoverage
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Global Deterministic Prediction System sample coverage
+ tags:
+ - gdps-temperature
+ /collections/gdps-temperature/coverage/domainset:
+ get:
+ description: Global Deterministic Prediction System sample
+ operationId: getGdps-temperatureCoverageDomainSet
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: https://raw.githubusercontent.com/tomkralidis/ogcapi-coverages-1/fix-cis/yaml-unresolved/schemas/cis_1.1/domainSet.yaml
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Global Deterministic Prediction System sample coverage domain set
+ tags:
+ - gdps-temperature
+ /collections/gdps-temperature/coverage/rangetype:
+ get:
+ description: Global Deterministic Prediction System sample
+ operationId: getGdps-temperatureCoverageRangeType
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: https://raw.githubusercontent.com/tomkralidis/ogcapi-coverages-1/fix-cis/yaml-unresolved/schemas/cis_1.1/rangeType.yaml
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Global Deterministic Prediction System sample coverage range type
+ tags:
+ - gdps-temperature
+ /collections/lakes:
+ get:
+ description: lakes of the world, public domain
+ operationId: describeLakesCollection
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Large Lakes metadata
+ tags:
+ - lakes
+ /collections/lakes/items:
+ get:
+ description: lakes of the world, public domain
+ operationId: getLakesFeatures
+ parameters:
+ - *id001
+ - *id002
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/limit
+ - description: The properties that should be included for each feature. The
+ parameter value is a comma-separated list of property names.
+ explode: false
+ in: query
+ name: properties
+ required: false
+ schema:
+ items:
+ enum:
+ - id
+ - scalerank
+ - name
+ - name_alt
+ - admin
+ - featureclass
+ type: string
+ type: array
+ style: form
+ - $ref: '#/components/parameters/skipGeometry'
+ - $ref: https://raw.githubusercontent.com/opengeospatial/ogcapi-records/master/core/openapi/parameters/sortby.yaml
+ - $ref: '#/components/parameters/startindex'
+ - explode: false
+ in: query
+ name: id
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: scalerank
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: name
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: name_alt
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: admin
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: featureclass
+ required: false
+ schema:
+ type: string
+ style: form
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Large Lakes items
+ tags:
+ - lakes
+ /collections/lakes/items/{featureId}:
+ get:
+ description: lakes of the world, public domain
+ operationId: getLakesFeature
+ parameters:
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Large Lakes item by id
+ tags:
+ - lakes
+ /collections/lakes/queryables:
+ get:
+ description: lakes of the world, public domain
+ operationId: getLakesQueryables
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: '#/components/responses/Queryables'
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Large Lakes queryables
+ tags:
+ - lakes
+ /collections/obs:
+ get:
+ description: My cool observations
+ operationId: describeObsCollection
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Observations metadata
+ tags:
+ - obs
+ /collections/obs/items:
+ get:
+ description: My cool observations
+ operationId: getObsFeatures
+ parameters:
+ - *id001
+ - *id002
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/bbox
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/limit
+ - description: The properties that should be included for each feature. The
+ parameter value is a comma-separated list of property names.
+ explode: false
+ in: query
+ name: properties
+ required: false
+ schema:
+ items:
+ enum:
+ - id
+ - stn_id
+ - datetime
+ - value
+ - lat
+ - long
+ type: string
+ type: array
+ style: form
+ - $ref: '#/components/parameters/skipGeometry'
+ - $ref: https://raw.githubusercontent.com/opengeospatial/ogcapi-records/master/core/openapi/parameters/sortby.yaml
+ - $ref: '#/components/parameters/startindex'
+ - explode: false
+ in: query
+ name: id
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: stn_id
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: datetime
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: value
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: lat
+ required: false
+ schema:
+ type: string
+ style: form
+ - explode: false
+ in: query
+ name: long
+ required: false
+ schema:
+ type: string
+ style: form
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Observations items
+ tags:
+ - obs
+ /collections/obs/items/{featureId}:
+ get:
+ description: My cool observations
+ operationId: getObsFeature
+ parameters:
+ - $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Observations item by id
+ tags:
+ - obs
+ /collections/obs/queryables:
+ get:
+ description: My cool observations
+ operationId: getObsQueryables
+ parameters:
+ - *id001
+ - *id002
+ responses:
+ '200':
+ $ref: '#/components/responses/Queryables'
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: Get Observations queryables
+ tags:
+ - obs
+ /conformance:
+ get:
+ description: API conformance definition
+ operationId: getConformanceDeclaration
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ConformanceDeclaration
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
+ summary: API conformance definition
+ tags:
+ - server
+ /openapi:
+ get:
+ description: This document
+ operationId: getOpenapi
+ parameters:
+ - $ref: '#/components/parameters/f'
+ - $ref: '#/components/parameters/lang'
+ - description: UI to render the OpenAPI document
+ explode: false
+ in: query
+ name: ui
+ required: false
+ schema:
+ default: swagger
+ enum:
+ - swagger
+ - redoc
+ type: string
+ style: form
+ responses:
+ '200':
+ $ref: '#/components/responses/200'
+ '400':
+ $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
+ default:
+ $ref: '#/components/responses/default'
+ summary: This document
+ tags:
+ - server
+ /processes:
+ get:
+ description: Processes
+ operationId: getProcesses
+ parameters:
+ - $ref: '#/components/parameters/f'
+ responses:
+ '200':
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/responses/ProcessList.yaml
+ default:
+ $ref: '#/components/responses/default'
+ summary: Processes
+ tags:
+ - server
+ /processes/hello-world:
+ get:
+ description: An example process that takes a name as input, and echoes it back
+ as output. Intended to demonstrate a simple process with a single literal
+ input.
+ operationId: describeHello-worldProcess
+ parameters:
+ - $ref: '#/components/parameters/f'
+ responses:
+ '200':
+ $ref: '#/components/responses/200'
+ default:
+ $ref: '#/components/responses/default'
+ summary: Get process metadata
+ tags:
+ - hello-world
+ /processes/hello-world/execution:
+ post:
+ description: An example process that takes a name as input, and echoes it back
+ as output. Intended to demonstrate a simple process with a single literal
+ input.
+ operationId: executeHello-worldJob
+ requestBody:
+ content:
+ application/json:
+ example:
+ inputs:
+ message: An optional message.
+ name: World
+ schema:
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/schemas/execute.yaml
+ description: Mandatory execute request JSON
+ required: true
+ responses:
+ '200':
+ $ref: '#/components/responses/200'
+ '201':
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/responses/ExecuteAsync.yaml
+ '404':
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/responses/NotFound.yaml
+ '500':
+ $ref: http://schemas.opengis.net/ogcapi/processes/part1/1.0/openapi/responses/ServerError.yaml
+ default:
+ $ref: '#/components/responses/default'
+ summary: Process Hello World execution
+ tags:
+ - hello-world
+ /stac:
+ get:
+ description: SpatioTemporal Asset Catalog
+ operationId: getStacCatalog
+ parameters: []
+ responses:
+ '200':
+ $ref: '#/components/responses/200'
+ default:
+ $ref: '#/components/responses/default'
+ summary: SpatioTemporal Asset Catalog
+ tags:
+ - stac
+servers:
+- description: pygeoapi provides an API to geospatial data
+ url: http://localhost:5000
+tags:
+- description: pygeoapi provides an API to geospatial data
+ externalDocs:
+ description: information
+ url: https://example.org
+ name: server
+- description: SpatioTemporal Asset Catalog
+ name: stac
+- description: My cool observations
+ name: obs
+- description: lakes of the world, public domain
+ name: lakes
+- description: Global Deterministic Prediction System sample
+ name: gdps-temperature
+- description: Sample metadata records from open.canada.ca
+ name: canada-metadata
+- description: An example process that takes a name as input, and echoes it back as
+ output. Intended to demonstrate a simple process with a single literal input.
+ name: hello-world
+
diff --git a/pygeoapi/__init__.py b/pygeoapi/__init__.py
index cbd6962..9d32872 100644
--- a/pygeoapi/__init__.py
+++ b/pygeoapi/__init__.py
@@ -43,6 +43,7 @@ def cli():
@cli.command()
@click.option('--flask', 'server', flag_value="flask", default=True)
@click.option('--starlette', 'server', flag_value="starlette")
+@click.option('--django', 'server', flag_value="django")
@click.pass_context
def serve(ctx, server):
"""Run the server with different daemon type (--flask is the default)"""
@@ -55,8 +56,11 @@ def serve(ctx, server):
from pygeoapi.starlette_app import serve as serve_starlette
ctx.forward(serve_starlette)
ctx.invoke(serve_starlette)
+ elif server == "django":
+ from pygeoapi.django_app import main as serve_django
+ ctx.invoke(serve_django)
else:
- raise click.ClickException('--flask/--starlette is required')
+ raise click.ClickException('--flask/--starlette/--django is required')
cli.add_command(config)
diff --git a/pygeoapi/api.py b/pygeoapi/api.py
index b761f7d..35ca548 100644
--- a/pygeoapi/api.py
+++ b/pygeoapi/api.py
@@ -276,6 +276,8 @@ class APIRequest:
self._path_info = request.scope['path'].strip('/')
elif hasattr(request.headers, 'environ'):
self._path_info = request.headers.environ['PATH_INFO'].strip('/')
+ elif hasattr(request, 'path_info'):
+ self._path_info = request.path_info
# Extract locale from params or headers
self._raw_locale, self._locale = self._get_locale(request.headers,
@@ -309,17 +311,22 @@ class APIRequest:
# Set data from Flask request
api_req._data = request.data
elif hasattr(request, 'body'):
- try:
- import nest_asyncio
- nest_asyncio.apply()
- # Set data from Starlette request after async
- # coroutine completion
- # TODO: this now blocks, but once Flask v2 with async support
- # has been implemented, with_data() can become async too
- loop = asyncio.get_event_loop()
- api_req._data = loop.run_until_complete(request.body())
- except ModuleNotFoundError:
- LOGGER.error("Module nest-asyncio not found")
+ if "django" in str(request.__class__):
+ # Set data from Django request
+ api_req._data = request.body
+ else:
+ try:
+ import nest_asyncio
+ nest_asyncio.apply()
+ # Set data from Starlette request after async
+ # coroutine completion
+ # TODO:
+ # this now blocks, but once Flask v2 with async support
+ # has been implemented, with_data() can become async too
+ loop = asyncio.get_event_loop()
+ api_req._data = loop.run_until_complete(request.body())
+ except ModuleNotFoundError:
+ LOGGER.error("Module nest-asyncio not found")
return api_req
@staticmethod
@@ -337,6 +344,12 @@ class APIRequest:
elif hasattr(request, 'query_params'):
# Return ImmutableMultiDict from Starlette request
return request.query_params
+ elif hasattr(request, 'GET'):
+ # Return QueryDict from Django GET request
+ return request.GET
+ elif hasattr(request, 'POST'):
+ # Return QueryDict from Django GET request
+ return request.POST
LOGGER.debug('No query parameters found')
return {}
diff --git a/pygeoapi/db.sqlite3 b/pygeoapi/db.sqlite3
new file mode 100644
index 0000000..e69de29
diff --git a/pygeoapi/django_app.py b/pygeoapi/django_app.py
new file mode 100644
index 0000000..69f1b0c
--- /dev/null
+++ b/pygeoapi/django_app.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+from pathlib import Path
+
+
+def config():
+ from pygeoapi.util import yaml_load
+
+ if not os.environ.get('PYGEOAPI_CONFIG'):
+ raise RuntimeError('PYGEOAPI_CONFIG environment variable not set')
+
+ with open(os.environ.get('PYGEOAPI_CONFIG'), encoding='utf8') as fh:
+ CONFIG = yaml_load(fh)
+
+ return CONFIG
+
+
+def main():
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_pygeoapi.settings')
+ django_app_path = Path(os.path.dirname(__file__))
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+
+ CONFIG = config()
+ sys.argv = [str(django_app_path / "django_app.py"),
+ "runserver",
+ f"{CONFIG['server']['bind'].get('host')}:"
+ f"{CONFIG['server']['bind'].get('port')}"]
+ sys.path.append(str(django_app_path))
+
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/pygeoapi/django_pygeoapi/__init__.py b/pygeoapi/django_pygeoapi/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pygeoapi/django_pygeoapi/sample_project/manage.py b/pygeoapi/django_pygeoapi/sample_project/manage.py
new file mode 100755
index 0000000..6af9e26
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample_project.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/pygeoapi/django_pygeoapi/sample_project/pygeoapi-config.yml b/pygeoapi/django_pygeoapi/sample_project/pygeoapi-config.yml
new file mode 100644
index 0000000..8b7515b
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/pygeoapi-config.yml
@@ -0,0 +1,275 @@
+# =================================================================
+#
+# Authors: Tom Kralidis
+#
+# Copyright (c) 2020 Tom Kralidis
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# =================================================================
+
+server:
+ bind:
+ host: 0.0.0.0
+ port: 8000
+ url: http://localhost:8000/sample-project
+ mimetype: application/json; charset=UTF-8
+ encoding: utf-8
+ gzip: false
+ languages:
+ # First language is the default language
+ - en-US
+ - fr-CA
+ # cors: true
+ pretty_print: true
+ limit: 10
+ # templates:
+ # path: /path/to/Jinja2/templates
+ # static: /path/to/static/folder # css/js/img
+ map:
+ url: https://tile.openstreetmap.org/{z}/{x}/{y}.png
+ attribution: '© OpenStreetMap contributors'
+# manager:
+# name: TinyDB
+# connection: /tmp/pygeoapi-process-manager.db
+# output_dir: /tmp/
+ # ogc_schemas_location: /opt/schemas.opengis.net
+
+logging:
+ level: ERROR
+ #logfile: /tmp/pygeoapi.log
+
+metadata:
+ identification:
+ title:
+ en: pygeoapi default instance
+ fr: instance par défaut de pygeoapi
+ description:
+ en: pygeoapi provides an API to geospatial data
+ fr: pygeoapi fournit une API aux données géospatiales
+ keywords:
+ en:
+ - geospatial
+ - data
+ - api
+ fr:
+ - géospatiale
+ - données
+ - api
+ keywords_type: theme
+ terms_of_service: https://creativecommons.org/licenses/by/4.0/
+ url: https://example.org
+ license:
+ name: CC-BY 4.0 license
+ url: https://creativecommons.org/licenses/by/4.0/
+ provider:
+ name: Organization Name
+ url: https://pygeoapi.io
+ contact:
+ name: Lastname, Firstname
+ position: Position Title
+ address: Mailing Address
+ city: City
+ stateorprovince: Administrative Area
+ postalcode: Zip or Postal Code
+ country: Country
+ phone: +xx-xxx-xxx-xxxx
+ fax: +xx-xxx-xxx-xxxx
+ email: you@example.org
+ url: Contact URL
+ hours: Mo-Fr 08:00-17:00
+ instructions: During hours of service. Off on weekends.
+ role: pointOfContact
+
+resources:
+ obs:
+ type: collection
+ title: Observations
+ description: My cool observations
+ keywords:
+ - observations
+ - monitoring
+ context:
+ - datetime: https://schema.org/DateTime
+ - vocab: https://example.com/vocab#
+ stn_id: "vocab:stn_id"
+ value: "vocab:value"
+ links:
+ - type: text/csv
+ rel: canonical
+ title: data
+ href: https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv
+ hreflang: en-US
+ - type: text/csv
+ rel: alternate
+ title: data
+ href: https://raw.githubusercontent.com/mapserver/mapserver/branch-7-0/msautotest/wxs/data/obs.csv
+ hreflang: en-US
+ extents:
+ spatial:
+ bbox: [-180,-90,180,90]
+ crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
+ temporal:
+ begin: 2000-10-30T18:24:39Z
+ end: 2007-10-30T08:57:29Z
+ providers:
+ - type: feature
+ name: CSV
+ data: tests/data/obs.csv
+ id_field: id
+ geometry:
+ x_field: long
+ y_field: lat
+
+ lakes:
+ type: collection
+ title:
+ en: Large Lakes
+ fr: Grands Lacs
+ description:
+ en: lakes of the world, public domain
+ fr: lacs du monde, domaine public
+ keywords:
+ en:
+ - lakes
+ - water bodies
+ fr:
+ - lacs
+ - plans d'eau
+ links:
+ - type: text/html
+ rel: canonical
+ title: information
+ href: http://www.naturalearthdata.com/
+ hreflang: en-US
+ extents:
+ spatial:
+ bbox: [-180,-90,180,90]
+ crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
+ temporal:
+ begin: 2011-11-11T11:11:11Z
+ end: null # or empty (either means open ended)
+ providers:
+ - type: feature
+ name: GeoJSON
+ data: tests/data/ne_110m_lakes.geojson
+ id_field: id
+ title_field: name
+
+ gdps-temperature:
+ type: collection
+ title: Global Deterministic Prediction System sample
+ description: Global Deterministic Prediction System sample
+ keywords:
+ - gdps
+ - global
+ extents:
+ spatial:
+ bbox: [-180,-90,180,90]
+ crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
+ links:
+ - type: text/html
+ rel: canonical
+ title: information
+ href: https://eccc-msc.github.io/open-data/msc-data/nwp_gdps/readme_gdps_en
+ hreflang: en-CA
+ providers:
+ - type: coverage
+ name: rasterio
+ data: tests/data/CMC_glb_TMP_TGL_2_latlon.15x.15_2020081000_P000.grib2
+ options:
+ DATA_ENCODING: COMPLEX_PACKING
+ format:
+ name: GRIB
+ mimetype: application/x-grib2
+
+ test-data:
+ type: stac-collection
+ title: pygeoapi test data
+ description: pygeoapi test data
+ keywords:
+ - poi
+ - portugal
+ links:
+ - type: text/html
+ rel: canonical
+ title: information
+ href: https://github.com/geopython/pygeoapi/tree/master/tests/data
+ hreflang: en-US
+ extents:
+ spatial:
+ bbox: [-180,-90,180,90]
+ crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
+ providers:
+ - type: stac
+ name: FileSystem
+ data: tests/data
+ file_types:
+ - .gpkg
+ - .sqlite
+ - .csv
+ - .grib2
+ - .tif
+ - .shp
+
+ canada-metadata:
+ type: collection
+ title:
+ en: Open Canada sample data
+ fr: Exemple de donn\u00e9es Canada Ouvert
+ description:
+ en: Sample metadata records from open.canada.ca
+ fr: Exemples d'enregistrements de m\u00e9tadonn\u00e9es sur ouvert.canada.ca
+ keywords:
+ en:
+ - canada
+ - open data
+ fr:
+ - canada
+ - donn\u00e9es ouvertes
+ links:
+ - type: text/html
+ rel: canonical
+ title: information
+ href: https://open.canada.ca/en/open-data
+ hreflang: en-CA
+ - type: text/html
+ rel: alternate
+ title: informations
+ href: https://ouvert.canada.ca/fr/donnees-ouvertes
+ hreflang: fr-CA
+ extents:
+ spatial:
+ bbox: [-180,-90,180,90]
+ crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
+ providers:
+ - type: record
+ name: TinyDBCatalogue
+ data: tests/data/open.canada.ca/sample-records.tinydb
+ id_field: externalId
+ time_field: recordCreated
+ title_field: title
+
+ hello-world:
+ type: process
+ processor:
+ name: HelloWorld
diff --git a/pygeoapi/django_pygeoapi/sample_project/sample_project/__init__.py b/pygeoapi/django_pygeoapi/sample_project/sample_project/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pygeoapi/django_pygeoapi/sample_project/sample_project/asgi.py b/pygeoapi/django_pygeoapi/sample_project/sample_project/asgi.py
new file mode 100644
index 0000000..8b03eb3
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/sample_project/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for sample_project project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample_project.settings')
+
+application = get_asgi_application()
diff --git a/pygeoapi/django_pygeoapi/sample_project/sample_project/settings.py b/pygeoapi/django_pygeoapi/sample_project/sample_project/settings.py
new file mode 100644
index 0000000..f12c215
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/sample_project/settings.py
@@ -0,0 +1,129 @@
+"""
+Django settings for sample_project project.
+
+Generated by 'django-admin startproject' using Django 3.2.12.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/3.2/ref/settings/
+"""
+
+from pathlib import Path
+from pygeoapi.django_app import config
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-um1sc7k4ovzdhp2r3kwz#%ta-l+kn$grk&9#7_(a0f)q$6u_ra' # noqa
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'sample_project.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'sample_project.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', # noqa
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', # noqa
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', # noqa
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', # noqa
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/3.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/3.2/howto/static-files/
+
+STATIC_URL = '/static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+# pygeoapi
+PYGEOAPI_CONFIG = config()
diff --git a/pygeoapi/django_pygeoapi/sample_project/sample_project/urls.py b/pygeoapi/django_pygeoapi/sample_project/sample_project/urls.py
new file mode 100644
index 0000000..a890da5
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/sample_project/urls.py
@@ -0,0 +1,24 @@
+"""sample_project URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/3.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path, include
+
+from pygeoapi.django_pygeoapi import urls as pygeoapi_urls
+
+urlpatterns = [
+ path('admin/', admin.site.urls),
+ path('sample-project/', include(pygeoapi_urls)),
+]
diff --git a/pygeoapi/django_pygeoapi/sample_project/sample_project/wsgi.py b/pygeoapi/django_pygeoapi/sample_project/sample_project/wsgi.py
new file mode 100644
index 0000000..97a1db8
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/sample_project/sample_project/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for sample_project project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample_project.settings')
+
+application = get_wsgi_application()
diff --git a/pygeoapi/django_pygeoapi/settings.py b/pygeoapi/django_pygeoapi/settings.py
new file mode 100644
index 0000000..000ddca
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/settings.py
@@ -0,0 +1,133 @@
+"""
+Django settings for django_pygeoapi project.
+
+Generated by 'django-admin startproject' using Django 2.2.18.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os
+# pygeoapi specific
+from pygeoapi.django_app import config
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = ")#cqm2jfato)gk((nm#%r7hn&aqy00_21pavfp=l8)4%cegb"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+]
+
+MIDDLEWARE = [
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+]
+
+ROOT_URLCONF = "django_pygeoapi.urls"
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "django_pygeoapi.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME":
+ "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa
+ },
+ {
+ "NAME":
+ "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME":
+ "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME":
+ "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATICFILES_DIRS = [
+ os.path.join(BASE_DIR, "static")
+]
+STATIC_ROOT = os.path.join(BASE_DIR, "assets")
+STATIC_URL = "/static/"
+
+# pygeoapi specific
+PYGEOAPI_CONFIG = config()
diff --git a/pygeoapi/django_pygeoapi/urls.py b/pygeoapi/django_pygeoapi/urls.py
new file mode 100644
index 0000000..29c1e3f
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/urls.py
@@ -0,0 +1,150 @@
+"""django_pygeoapi URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/2.2/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+
+from django.urls import (
+ path,
+)
+from django.conf import settings
+from django.conf.urls.static import static
+
+from . import views
+
+urlpatterns = [
+ path("", views.landing_page, name="landing-page"),
+ path("openapi/", views.openapi, name="openapi"),
+ path("conformance/", views.conformance, name="conformance"),
+ path("collections/", views.collections, name="collections"),
+ path(
+ "collections/",
+ views.collections,
+ name="collection-detail",
+ ),
+ path(
+ "collections//queryables/",
+ views.collection_queryables,
+ name="collection-queryables",
+ ),
+ path(
+ "collections//items/",
+ views.collection_items,
+ name="collection-items",
+ ),
+ path(
+ "collections//items/",
+ views.collection_item,
+ name="collection-item",
+ ),
+ path(
+ "collections//coverage/",
+ views.collection_coverage,
+ name="collection-coverage",
+ ),
+ path(
+ "collections//coverage/domainset/",
+ views.collection_coverage_domainset,
+ name="collection-coverage-domainset",
+ ),
+ path(
+ "collections//coverage/rangetype/",
+ views.collection_coverage_rangetype,
+ name="collection-coverage-rangetype",
+ ),
+ path(
+ "collections//tiles/",
+ views.collection_tiles,
+ name="collection-tiles",
+ ),
+ path(
+ "collections//tiles//metadata",
+ views.collection_tiles_metadata,
+ name="collection-tiles-metadata",
+ ),
+ path(
+ "collections//tiles/\
+ ///",
+ views.collection_item_tiles,
+ name="collection-item-tiles",
+ ),
+ path(
+ "collections//position",
+ views.get_collection_edr_query,
+ name="collection-edr-position",
+ ),
+ path(
+ "collections//area",
+ views.get_collection_edr_query,
+ name="collection-edr-area",
+ ),
+ path(
+ "collections//cube",
+ views.get_collection_edr_query,
+ name="collection-edr-cube",
+ ),
+ path(
+ "collections//trajectory",
+ views.get_collection_edr_query,
+ name="collection-edr-trajectory",
+ ),
+ path(
+ "collections//corridor",
+ views.get_collection_edr_query,
+ name="collection-edr-corridor",
+ ),
+ path(
+ "collections//instances//position",
+ views.get_collection_edr_query,
+ name="collection-edr-instance-position",
+ ),
+ path(
+ "collections//instances//area",
+ views.get_collection_edr_query,
+ name="collection-edr-instance-area",
+ ),
+ path(
+ "collections//instances//cube",
+ views.get_collection_edr_query,
+ name="collection-edr-instance-cube",
+ ),
+ path(
+ "collections//instances//trajectory", # noqa
+ views.get_collection_edr_query,
+ name="collection-edr-instance-trajectory",
+ ),
+ path(
+ "collections//instances//corridor",
+ views.get_collection_edr_query,
+ name="collection-edr-instance-corridor",
+ ),
+ path("processes/", views.processes, name="processes"),
+ path("processes/", views.processes, name="process-detail"),
+ path("jobs/", views.jobs, name="jobs"),
+ path("jobs/", views.jobs, name="job"),
+ path(
+ "jobs//results/",
+ views.job_results,
+ name="job-results",
+ ),
+ path(
+ "jobs//results/",
+ views.job_results_resource,
+ name="job-results-resource",
+ ),
+ path("stac/", views.stac_catalog_root, name="stac-catalog-root"),
+ path("stac/", views.stac_catalog_path, name="stac-catalog-path"),
+ path(
+ "stac/search/", views.stac_catalog_search, name="stac-catalog-search"
+ ),
+] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
diff --git a/pygeoapi/django_pygeoapi/views.py b/pygeoapi/django_pygeoapi/views.py
new file mode 100644
index 0000000..70b4ad7
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/views.py
@@ -0,0 +1,449 @@
+"""Integration module for Django"""
+from typing import Tuple, Dict, Mapping, Optional
+from django.conf import settings
+from django.http import HttpRequest, HttpResponse
+from pygeoapi.api import API
+from pygeoapi.openapi import get_oas
+
+
+def landing_page(request: HttpRequest) -> HttpResponse:
+ """
+ OGC API landing page endpoint
+
+ :request Django HTTP Request
+
+ :returns: Django HTTP Response
+ """
+
+ response_ = _feed_response(request, "landing_page")
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def openapi(request: HttpRequest) -> HttpResponse:
+ """
+ OpenAPI endpoint
+
+ :request Django HTTP Request
+
+ :returns: Django HTTP Response
+ """
+
+ openapi_config = get_oas(settings.PYGEOAPI_CONFIG)
+ response_ = _feed_response(request, "openapi", openapi_config)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def conformance(request: HttpRequest) -> HttpResponse:
+ """
+ OGC API conformance endpoint
+
+ :request Django HTTP Request
+
+ :returns: Django HTTP Response
+ """
+
+ response_ = _feed_response(request, "conformance")
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collections(
+ request: HttpRequest,
+ collection_id: Optional[str] = None,
+) -> HttpResponse:
+ """
+ OGC API collections endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP Response
+ """
+
+ response_ = _feed_response(request, "describe_collections", collection_id)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_queryables(
+ request: HttpRequest,
+ collection_id: Optional[str] = None,
+) -> HttpResponse:
+ """
+ OGC API collections queryables endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP Response
+ """
+
+ response_ = _feed_response(
+ request, "get_collection_queryables", collection_id
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_items(
+ request: HttpRequest,
+ collection_id: str,
+) -> HttpResponse:
+ """
+ OGC API collections items endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request,
+ "get_collection_items",
+ collection_id,
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_item(
+ request: HttpRequest,
+ collection_id: str,
+ item_id: str,
+) -> HttpResponse:
+ """
+ OGC API collections items endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+ :param item_id: item identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request, "get_collection_item", collection_id, item_id
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_coverage(
+ request: HttpRequest,
+ collection_id: str,
+) -> HttpResponse:
+ """
+ OGC API - Coverages coverage endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request, "get_collection_coverage", collection_id
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_coverage_domainset(
+ request: HttpRequest,
+ collection_id: str,
+) -> HttpResponse:
+ """
+ OGC API - Coverages coverage domainset endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request, "get_collection_coverage_domainset", collection_id
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_coverage_rangetype(
+ request: HttpRequest,
+ collection_id: str,
+) -> HttpResponse:
+ """
+ OGC API - Coverages coverage rangetype endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request, "get_collection_coverage_rangetype", collection_id
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_tiles(
+ request: HttpRequest,
+ collection_id: str,
+) -> HttpResponse:
+ """
+ OGC API - Tiles collection tiles endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(request, "get_collection_tiles", collection_id)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_tiles_metadata(
+ request: HttpRequest,
+ collection_id: str,
+ tileMatrixSetId: str,
+) -> HttpResponse:
+ """
+ OGC API - Tiles collection tiles metadata endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+ :param tileMatrixSetId: identifier of tile matrix set
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request,
+ "get_collection_tiles_metadata",
+ collection_id,
+ tileMatrixSetId,
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def collection_item_tiles(
+ request: HttpRequest,
+ collection_id: str,
+ tileMatrixSetId: str,
+ tileMatrix: str,
+ tileRow: str,
+ tileCol: str,
+) -> HttpResponse:
+ """
+ OGC API - Tiles collection tiles data endpoint
+
+ :request Django HTTP Request
+ :param collection_id: collection identifier
+ :param tileMatrixSetId: identifier of tile matrix set
+ :param tileMatrix: identifier of {z} matrix index
+ :param tileRow: identifier of {y} matrix index
+ :param tileCol: identifier of {x} matrix index
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(
+ request,
+ "get_collection_tiles_metadata",
+ collection_id,
+ tileMatrixSetId,
+ tileMatrix,
+ tileRow,
+ tileCol,
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def processes(
+ request: HttpRequest,
+ process_id: Optional[str] = None,
+) -> HttpResponse:
+ """
+ OGC API - Processes description endpoint
+
+ :request Django HTTP Request
+ :param process_id: process identifier
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(request, "describe_processes", process_id)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def jobs(
+ request: HttpRequest,
+ job_id: Optional[str] = None,
+) -> HttpResponse:
+ """
+ OGC API - Jobs endpoint
+
+ :request Django HTTP Request
+ :param process_id: process identifier
+ :param job_id: job identifier
+
+ :returns: Django HTTP response
+ """
+ response_ = _feed_response(request, "get_jobs", job_id)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def job_results(
+ request: HttpRequest,
+ job_id: Optional[str] = None,
+) -> HttpResponse:
+ """
+ OGC API - Job result endpoint
+
+ :request Django HTTP Request
+ :param job_id: job identifier
+
+ :returns: Django HTTP response
+ """
+ response_ = _feed_response(request, "get_job_result", job_id)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def job_results_resource(
+ request: HttpRequest,
+ process_id: str,
+ job_id: str,
+ resource: str,
+) -> HttpResponse:
+ """
+ OGC API - Job result resource endpoint
+
+ :request Django HTTP Request
+ :param job_id: job identifier
+ :param resource: job resource
+
+ :returns: Django HTTP response
+ """
+ response_ = _feed_response(
+ request,
+ "get_job_result_resource",
+ job_id,
+ resource
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def get_collection_edr_query(
+ request: HttpRequest,
+ collection_id: str,
+ instance_id: str,
+) -> HttpResponse:
+ """
+ OGC API - EDR endpoint
+
+ :request Django HTTP Request
+ :param job_id: job identifier
+ :param resource: job resource
+
+ :returns: Django HTTP response
+ """
+ query_type = request.path.split('/')[-1]
+ response_ = _feed_response(
+ request,
+ "get_collection_edr_query",
+ collection_id,
+ instance_id,
+ query_type
+ )
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def stac_catalog_root(request: HttpRequest) -> HttpResponse:
+ """
+ STAC root endpoint
+
+ :request Django HTTP Request
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(request, "get_stac_root")
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def stac_catalog_path(
+ request: HttpRequest,
+ path: str,
+) -> HttpResponse:
+ """
+ STAC path endpoint
+
+ :request Django HTTP Request
+ :param path: path
+
+ :returns: Django HTTP response
+ """
+
+ response_ = _feed_response(request, "get_stac_path", path)
+ response = _to_django_response(*response_)
+
+ return response
+
+
+def stac_catalog_search(request: HttpRequest) -> HttpResponse:
+ pass
+
+
+def _feed_response(
+ request: HttpRequest, api_definition: str, *args, **kwargs
+) -> Tuple[Dict, int, str]:
+ """Use pygeoapi api to process the input request"""
+ api_ = API(settings.PYGEOAPI_CONFIG)
+ api = getattr(api_, api_definition)
+ return api(request, *args, **kwargs)
+
+
+def _to_django_response(
+ headers: Mapping,
+ status_code: int,
+ content: str,
+) -> HttpResponse:
+ """Convert API payload to a django response"""
+ response = HttpResponse(content, status=status_code)
+ for key, value in headers.items():
+ response[key] = value
+ return response
diff --git a/pygeoapi/django_pygeoapi/wsgi.py b/pygeoapi/django_pygeoapi/wsgi.py
new file mode 100644
index 0000000..3407543
--- /dev/null
+++ b/pygeoapi/django_pygeoapi/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for django_pygeoapi project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_pygeoapi.settings")
+
+application = get_wsgi_application()
diff --git a/requirements-django.txt b/requirements-django.txt
new file mode 100644
index 0000000..efb1e80
--- /dev/null
+++ b/requirements-django.txt
@@ -0,0 +1,2 @@
+Django <= 4, > 3
+pydantic