| Developer Portal

Data catalogResourcesContactAbout the project

| Developer Portal

  • Data catalog
  • Resources
  • Contact
  • About the project
  • Cookies
  • The OpenEPI project partners
  • Knowit
  • Capto
  • Creative Commons
  • Open Future

2025 - Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license.

Back to how-to articles

Setting up the generic entity-attribute-backend

Last updated: June 24, 2025
Satellite view of Earth at night showing city lights, with a glowing server icon overlaid

Table of Contents

  1. Running the application
  2. Core concepts
  3. Configuring entities
  4. Using the entities
  5. Examples

This article will go through getting started with the generic entity-attribute-backend. For details and source code see https://github.com/openearthplatforminitiative/entity-attribute-backend

This backend provides a simple interface to manage entities and their attributes, allowing for easy storage, retrieval, and manipulation of data.This might be useful for applications that require a flexible and extensible way to handle various types of data entities.It is designed to be a quick way to get started with entity management without the need for complex database schemas or configurations.

Running the application

The simplest way of getting started using this generic backend is to use the provided docker-compose.yml that can be found in the github repository.

This will setup both the required PostgreSQL database and the backend application.

The following steps will start the application with the default configuration:

1. Clone the repository

SH
1git clone [email protected]:openearthplatforminitiative/entity-attribute-backend.git

2. Navigate to the project directory

SH
1cd entity-attribute-backend

3. Start the backend

SH
1docker compose up -d

The rest of this article assumes that the backend is started using docker compose and is running on http://localhost:8080. The api documentation can be found on http://localhost:8080/docs

Startup options

There are several options that can be tuned when starting the application. The following table lists the options and the outcome.

OptionDefaultTypeBehaviour
API_ROOT_PATH""StringChanges the root path of the generated api. Can be useful when running behind a reverse proxy
LOG_LEVELINFONOTSET, DEBUG, INFO, WARNING, ERROR, CRITICALSets the log level of the application
POSTGRES_USEReav_userStringUsername to connect to PostgreSQL with
POSTGRES_PASSWORDeav_passStringPassword to connect to PostgreSQL with
POSTGRES_DBeavStringThe name of the PostgreSQL database
POSTGRES_HOSTlocalhostStringHost where PostgreSQL is running
POSTGRES_PORT5432IntegerPort where PostgreSQL is running
POSTGRES_SCHEMApublicStringThe schema to use in the PostgreSQL database
RUN_MIGRATIONSTrueBooleanIndicates if alembic schema migrations should be run at startup.
IMPORT_ENTITIESFalseBooleanIndicates if entity definitions should be imported at startup.
IMPORT_CONFIG""StringLocation of entity definition files
ENABLE_ADMIN_APITrueBooleanIndicates if the admin api should be started. NB! There is no authentication to the admin api, so be careful if running this in production.
ENABLE_METRICSFalseBooleanIndicates if prometheus style metrics should be exposed.
ENABLE_ASSETSFalseBooleanIndicates if entities should support assets. E.g. uploading files
MAX_UPLOAD_SIZE10 * 1024 * 1024intSets the max file upload size in bytes.

All the above configuration options can be specified by using environment variables.

Core concepts

Entity Definition

An EntityDefinition defines the blueprint for a type of entity in your system. It specifies:

  • What kind of data this entity represents (e.g., "Incident", "Project", "Person")
  • What attributes it should have (e.g., "description", "location")
  • How it can relate to other entities (e.g., incidents can belong to projects)

Attribute Definition

An AttributeDefinition specifies the structure and rules for a single attribute that an entity of a given type can have. Each attribute has:

  • A name (e.g., "location")
  • A type (e.g., "STRING", "FLOAT", "GEOMETRY")
  • Whether it is required or optional
  • Whether it should be included in summaries or API responses

Entity

An Entity is an actual instance of a defined EntityDefinition. For example, an "Incident" called "River pollution" with a location and image.

Each entity:

  • Refers to its EntityDefinition type (e.g., "Incident")
  • Has associated attribute values (via Attribute objects)
  • Can relate to other entities (via EntityRelation)
  • May have linked assets (e.g., documents, images)

Entity Relation

An EntityRelation connects one entity to another — like a parent-child or logical grouping.

Each relation:

  • Has a source entity and a target entity
  • Is grouped in a collection_name (like a named relationship: "events", "attachments")
  • Supports flexible nesting (e.g., Project → Event → Incident)

Attribute

An Attribute holds the actual value of a field for a specific Entity.

Each attribute:

  • Links to its entity
  • Stores the value (e.g., name = "Gas Leak")
  • Is interpreted using the corresponding AttributeDefinition

Asset

An Asset represents a file or binary object (e.g., image, PDF, document) associated with an entity.

Each asset includes:

  • A unique ID
  • File metadata (filename, size, type, mimetype)
  • A binary blob or external file URL
  • A reference to the Entity it belongs to

Configuring entities

By default there are no configured entities, and when starting the application for the first time it needs to be configured in order to be usable.

There are two ways of configuring the entities:

      With the admin api
      By importing entity definitions at startup

The recommended approach is to use the admin api for exploring and trying the entities, but import at startup for production use. The admin api should be disabled in production.

When starting the application with no entities defined, the api documentation will look like the following

Default endpoints in api with no entities defined

Using the admin api

The documentation for the admin api can be found (if enabled) on http://localhost:8080/docs

Defining an entity with the admin api

SH
1curl -X 'POST' \
2  'http://localhost:8080/v1/admin/entity_definitions' \
3  -H 'accept: application/json' \
4  -H 'Content-Type: application/json' \
5  -d '{
6  "name": "Incident",
7  "collection_name": "incidents",
8  "apiEndpoints": ["LIST", "GET", "POST", "PUT", "DELETE"],
9  "returnSummaryOnCollection": true,
10  "supportsAssets": false,
11  "requiredAttributes": [
12    {
13      "name": "title",
14      "type": "STRING",
15      "includeInSummary": true
16    },
17    {
18      "name": "location",
19      "type": "GEOMETRY",
20      "includeInSummary": false
21    }
22  ],
23  "optionalAttributes": [],
24  "relatedEntities": []
25}'

Importing definitions at startup

Save the following json-content to the file /home/user/my_definitions/00_incident.json

JSON
1{
2  "name": "Incident",
3  "collection_name": "incidents",
4  "apiEndpoints": ["LIST", "GET", "POST", "PUT", "DELETE"],
5  "returnSummaryOnCollection": true,
6  "supportsAssets": false,
7  "requiredAttributes": [
8    {
9      "name": "title",
10      "type": "STRING",
11      "includeInSummary": true
12    },
13    {
14      "name": "location",
15      "type": "GEOMETRY",
16      "includeInSummary": false
17    }
18  ],
19  "optionalAttributes": [],
20  "relatedEntities": []
21}

Assuming you save your entitydefinitions in the folder /home/user/my_definitions/ you can set the following environment variables in order to import entity definitions at startup:

SH
1IMPORT_ENTITIES=true
2IMPORT_CONFIG=/home/user/my_definitions/

The files in the directory will be imported in order of the naming of the files. So be sure to order the files so that any relations are imported before they are referenced.

After importing the Incident entity defined above, the api documentation should look like the following:

Api documentation after importing the Incident entity

Assets

Assets can be files that are linked to an entity. E.g an image or a pdf document.

In order to take advantage of assets, you first need to enable assets in the backend, by defining the environment variable.

SH
1ENABLE_ASSETS=true

When the backend is started with assets enabled, entities can be marked as supporting assets.

Create the incident entity with support for assets

JSON
1{
2  "name": "Incident",
3  "collection_name": "incidents",
4  "apiEndpoints": ["LIST", "GET", "POST", "PUT", "DELETE"],
5  "returnSummaryOnCollection": true,
6  "supportsAssets": true, 
7  "requiredAttributes": [
8    {
9      "name": "title",
10      "type": "STRING",
11      "includeInSummary": true
12    },
13    {
14      "name": "location",
15      "type": "GEOMETRY",
16      "includeInSummary": false
17    }
18  ],
19  "optionalAttributes": [],
20  "relatedEntities": []
21}

Note that "supportsAssets": true enables assets for this entity.

After importing the above entity with assets enabled, the api (without the admin api) will look like the following

Api with support for assets

Relations

Relations can be used to connect one entity to another. An example can be that an Event might have many Incidents related to it.

These can be defined like the following. Note that the target relation must be defined before the source entity.

00_incident.json

JSON
1{
2    "name": "Incident",
3    "collection_name": "incidents",
4    "apiEndpoints": ["GET"],
5    "returnSummaryOnCollection": true,
6    "supportsAssets": false,
7    "requiredAttributes": [
8        {
9            "name": "name",
10            "type": "STRING",
11            "includeInSummary": true
12        },
13        {
14            "name": "description",
15            "type": "STRING"
16        },
17        {
18            "name": "location",
19            "type": "GEOMETRY"
20        }
21    ],
22    "optionalAttributes": [],
23    "relatedEntities": []
24}
25

01_event.json

JSON
1{
2  "name": "Event",
3  "collection_name": "events",
4  "apiEndpoints": ["LIST","GET", "POST"],
5  "returnSummaryOnCollection": true,
6  "requiredAttributes": [
7    {
8      "name": "name",
9      "type": "STRING",
10      "includeInSummary": true
11    },
12    {
13      "name": "description",
14      "type": "STRING"
15    }
16  ],
17  "optionalAttributes": [],
18  "relatedEntities": [
19    {
20      "entity": "Incident",
21      "collection_name": "incidents",
22      "apiEndpoints": ["LIST", "POST"]
23    }
24  ]
25}

Note that you can specify the api endpoints for the relations specifically.

The above configuration will (assets are not enabled) will result in the following api

API showing relations

Using the entities

After importing the entities, the api will be fully functioning an working like a normal REST api, depending on the apiEndpoints defined for the entities.

Getting all incidents

SH
1curl -X 'GET' 'http://localhost:8080/v1/incidents'

Posting an incident

SH
1curl -X 'POST' \
2  'http://localhost:8080/v1/incidents' \
3  -H 'accept: application/json' \
4  -H 'Content-Type: application/json' \
5  -d '{
6  "title": "River pollution",
7  "location": {
8    "type": "Point",
9    "coordinates": [
10      10,
11      60
12    ]
13  }
14}'

Examples

The following are examples of a definition of a backend for recording environmental incidents, and organizing them in projects and through events.

00_incident.json

JSON
1{
2    "name": "Incident",
3    "collection_name": "incidents",
4    "apiEndpoints": ["GET", "PUT"],
5    "returnSummaryOnCollection": true,
6    "supportsAssets": true,
7    "requiredAttributes": [
8        {
9            "name": "name",
10            "type": "STRING",
11            "includeInSummary": true
12        },
13        {
14            "name": "description",
15            "type": "STRING"
16        },
17        {
18            "name": "location",
19            "type": "GEOMETRY"
20        }
21    ],
22    "optionalAttributes": [],
23    "relatedEntities": []
24}
25

01_event.json

JSON
1{
2  "name": "Event",
3  "collection_name": "events",
4  "apiEndpoints": ["LIST","GET", "POST", "PUT", "DELETE"],
5  "returnSummaryOnCollection": true,
6  "requiredAttributes": [
7    {
8      "name": "name",
9      "type": "STRING",
10      "includeInSummary": true
11    },
12    {
13      "name": "description",
14      "type": "STRING"
15    }
16  ],
17  "optionalAttributes": [],
18  "relatedEntities": [
19    {
20      "entity": "Incident",
21      "collection_name": "incidents",
22      "apiEndpoints": ["LIST", "POST", "GET"]
23    }
24  ]
25}

02_project.json

JSON
1{
2    "name": "Project",
3    "collection_name": "projects",
4    "apiEndpoints": ["LIST", "GET", "POST", "PUT"],
5    "returnSummaryOnCollection": true,
6    "requiredAttributes": [
7        {
8            "name": "name",
9            "type": "STRING",
10            "includeInSummary": true
11        }
12    ],
13    "optionalAttributes": [
14        {
15            "name": "description",
16            "type": "STRING"
17        }
18    ],
19    "relatedEntities": [
20        {
21            "entity": "Event",
22            "collection_name": "events",
23            "apiEndpoints": ["LIST", "POST", "PUT", "DELETE", "GET"]
24        }
25    ]
26}


Last updated: June 24, 2025

Latest How-To's

Getting started using Global Forest Watch Data API

Getting started using Global Forest Watch Data API

Getting started using Map Components

Getting started using Map Components

Natural Forest Map  x  Global Forest Watch API

Natural Forest Map x Global Forest Watch API