Skip to content

fsdb_rest_api

plantdb.server.cli.fsdb_rest_api Link

FSDB REST API - Serve Plant Database through RESTful Endpoints

This module provides a RESTful API server for interacting with a local plant database (FSDB). It is designed for the ROMI project and facilitates efficient data handling and retrieval of plant-related datasets. The server enables users to query and manage plant scans, images, point clouds, and other related data files.

Key Features
  • Serve a local plant database (FSDB) through RESTful API endpoints.
  • Manage plant scans and related data, including images, point clouds, and meshes.
  • Retrieve and manage dataset files with various configurations.
  • Run in test mode with optional preconfigured datasets or an empty test database.
  • Lightweight server setup using Flask, with options for debugging and CORS support.
Environment Variables
  • ROMI_DB: Path to the directory containing the FSDB. Default: '/myapp/db' (container)
  • PLANTDB_API_PREFIX: Prefix for the REST API URL. Default is empty.
  • PLANTDB_API_SSL: Enable SSL to use an HTTPS scheme. Default is False.
  • FLASK_SECRET_KEY: The secret key to use with flask. Default to random (32 bits secret).
  • JWT_SECRET_KEY: The secret key to use with JWT token generator. Default to random (32 bits secret).
Usage Examples

To start the REST API server for a local plant database:

python fsdb_rest_api.py --db_location /path/to/your/database --host 127.0.0.1 --port 8080 --debug

To run the server with a temporary test database in debug mode:

python fsdb_rest_api.py --test --debug

RESTful endpoints include: - /scans: List all scans available in the database. - /files/<path:path>: Retrieve files from the database. - /image/<scan_id>/<fileset_id>/<file_id>: Access specific images. - /pointcloud/<scan_id>/<fileset_id>/<file_id>: Access specific point clouds. - /mesh/<scan_id>/<fileset_id>/<file_id>: Retrieve related meshes.

For detailed command-line parameters, use the --help flag:

python fsdb_rest_api.py --help

main Link

main()

Entry point for the REST API server.

Parses command line arguments, builds the Flask application, and starts the development server with the supplied host/port and debug settings.

Source code in plantdb/server/cli/fsdb_rest_api.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
def main():
    """Entry point for the REST API server.

    Parses command line arguments, builds the Flask application, and starts the development server
    with the supplied host/port and debug settings.
    """
    parser = parsing()
    args = parser.parse_args()

    app = rest_api(
        db_path=args.db_location,
        proxy=args.proxy,
        log_level=args.log_level,
        test=args.test,
        empty=args.empty,
        models=args.models,
    )
    # Start the Flask application:
    app.run(host=args.host, port=args.port, debug=args.debug)

parsing Link

parsing()

Create and configure an argument parser for a REST API server.

Returns:

Type Description
ArgumentParser

The configured argument parser capable of parsing and retrieving command-line arguments.

Source code in plantdb/server/cli/fsdb_rest_api.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def parsing() -> argparse.ArgumentParser:
    """
    Create and configure an argument parser for a REST API server.

    Returns
    -------
    argparse.ArgumentParser
        The configured argument parser capable of parsing and retrieving command-line arguments.
    """
    parser = argparse.ArgumentParser(description='Serve a local plantdb database (FSDB) through a REST API.')
    parser.add_argument('-db', '--db_location', type=str, default=os.environ.get("ROMI_DB", None),
                        help='location of the database to serve.')

    app_args = parser.add_argument_group("webserver arguments")
    app_args.add_argument('--host', type=str, default="0.0.0.0",
                          help="hostname to listen on; defaults to '0.0.0.0'.")
    app_args.add_argument('--port', type=int, default=5000,
                          help="port of the webserver; defaults to '5000'.")
    app_args.add_argument('--debug', action='store_true',
                          help="enable debug mode.")
    app_args.add_argument('--proxy', action='store_true',
                          help="use when the server sits behind a reverse proxy.")

    misc_args = parser.add_argument_group("other arguments")
    misc_args.add_argument("--test", action='store_true',
                           help="set up a temporary test database before starting the REST API.")
    misc_args.add_argument("--empty", action='store_true',
                           help="do not populate the test database with toy datasets.")
    misc_args.add_argument("--models", action='store_true',
                           help="include trained CNN model in the test database.")

    log_opt = parser.add_argument_group("logging options")
    log_opt.add_argument("--log-level", dest="log_level", type=str, default=DEFAULT_LOG_LEVEL, choices=LOG_LEVELS,
                         help="logging level; defaults to 'INFO'.")

    return parser

rest_api Link

rest_api(db_path, proxy=False, url_prefix='', ssl=False, log_level=DEFAULT_LOG_LEVEL, test=False, empty=False, models=False)

Initialize and configure a RESTful API server for Plant Database querying.

This function sets up a Flask application with various RESTful endpoints to enable interaction with a local Plant Database (FSDB). RESTful routes are added for managing and retrieving various datasets and configurations, providing an interface for working with plant scans and related files. The application can be run in test mode with optional configurations for using sample datasets.

Parameters:

Name Type Description Default
db_path str or Path or None

The path to the local plant database to be served. If set to "/none", the server will raise an error and terminate unless the path is appropriately overridden in test mode. If None, requires test=True and a temporary folder will be created.

required
proxy bool

Boolean flag indicating whether the application is behind a reverse proxy, False by default.

False
url_prefix str

Prefix for all endpoints, by default ""

''
log_level str

The logging level to use for the application. Defaults to DEFAULT_LOG_LEVEL.

DEFAULT_LOG_LEVEL
test bool

A boolean flag to specify if the application should run in test mode. When enabled, a test database will be instantiated with sample datasets or an empty configuration if specified. Defaults to False.

False
empty bool

A boolean flag to specify whether the test database should be instantiated without any datasets or configurations. Defaults to False.

False
models bool

A boolean flag to specify whether the test database should be populated with trained CNN models. Defaults to False.

False
Source code in plantdb/server/cli/fsdb_rest_api.py
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
def rest_api(db_path: Optional[Union[str, Path]], proxy: bool = False, url_prefix: str = "", ssl: bool = False,
             log_level: str = DEFAULT_LOG_LEVEL, test: bool = False, empty: bool = False,
             models: bool = False) -> Flask:
    """Initialize and configure a RESTful API server for Plant Database querying.

    This function sets up a Flask application with various RESTful endpoints to enable interaction with a
    local Plant Database (FSDB).
    RESTful routes are added for managing and retrieving various datasets and configurations, providing
    an interface for working with plant scans and related files. The application can be run in test
    mode with optional configurations for using sample datasets.

    Parameters
    ----------
    db_path : str or pathlib.Path or None
        The path to the local plant database to be served. If set to "/none", the server will raise
        an error and terminate unless the path is appropriately overridden in test mode.
        If `None`, requires `test=True` and a temporary folder will be created.
    proxy : bool, optional
        Boolean flag indicating whether the application is behind a reverse proxy, ``False`` by default.
    url_prefix : str, optional
        Prefix for all endpoints, by default ""
    log_level : str, optional
        The logging level to use for the application. Defaults to ``DEFAULT_LOG_LEVEL``.
    test : bool, optional
        A boolean flag to specify if the application should run in test mode. When enabled, a test
        database will be instantiated with sample datasets or an empty configuration if specified.
         Defaults to ``False``.
    empty : bool, optional
        A boolean flag to specify whether the test database should be instantiated without any
        datasets or configurations. Defaults to ``False``.
    models : bool, optional
        A boolean flag to specify whether the test database should be populated with trained CNN models.
        Defaults to ``False``.
    """
    wlogger = logging.getLogger('werkzeug')
    logger = get_logger("fsdb_rest_api", log_level=log_level)

    # 1 - Application and API configuration
    secret_key = _get_env_secret("FLASK_SECRET_KEY", logger)
    app = _configure_app(secret_key, ssl=ssl)
    api = _configure_api(app, proxy, url_prefix, logger)

    # 2 - Handle test mode
    if test:
        db_path = _setup_test_database(empty=empty, models=models, db_path=db_path, logger=logger)

        def _cleanup() -> None:
            logger.info(f"Cleaning up temporary database directory at '{db_path}'.")
            try:
                shutil.rmtree(db_path)
                logger.info("Temporary directory removed.")
            except OSError as exc:
                logger.error(f"Error removing temporary directory: {exc!s}")

        atexit.register(_cleanup)

    # 3 - Validate path
    if not db_path:
        logger.error(
            "No path to the local PlantDB was specified; aborting startup."
        )
        logger.info(
            "Set the environment variable 'ROMI_DB' or use the '--db_location' CLI argument."
        )
        sleep(1)
        sys.exit("Wrong database location!")

    # 4 - Database connection
    jwt_key = _get_env_secret("JWT_SECRET_KEY", logger)
    db = FSDB(
        db_path,
        session_manager=JWTSessionManager(secret_key=jwt_key),
    )
    logger.info(f"Connecting to local plant database at '{db.path()}'.")
    db.connect()
    logger.info(
        f"Found {len(db.list_scans(owner_only=False))} scans to serve in the local database."
    )

    # 5 - Register resources
    _register_resources(api, db, logger)

    return app