Skip to content

fsdb_rest_api

FSDB REST API - Serve Plant Database through RESTful EndpointsLink

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 FeaturesLink

  • 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 VariablesLink

  • ROMI_DB: Path to the directory containing the FSDB. Default: '/myapp/db' (container)
  • 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 (64 bits secret).
  • JWT_SECRET_KEY: The secret key to use with JSON Web Token generator. Default to random (64 bits secret).
  • SESSION_TIMEOUT: Session JWT validity duration in seconds. Default 900 seconds (15 min).
  • REFRESH_TIMEOUT: Refresh JWT validity duration in seconds. Default 86400 seconds (1 day).
  • MAX_SESSION: The maximum number of concurrent sessions to allow. Default 10.

Usage ExamplesLink

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

fsdb_rest_api -db /path/to/your/database --host 127.0.0.1 --port 8080

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

fsdb_rest_api --test --debug

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

fsdb_rest_api --help

main Link

main(host, port, debug, proxy, api_prefix, db_path, test, empty, models, log_level)

FSDB REST API - Serve Plant Database through RESTful Endpoints.

Source code in plantdb/server/cli/fsdb_rest_api.py
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
@click.command(context_settings=dict(help_option_names=["-h", "--help"]))
@click.option(
    "--host",
    default="0.0.0.0",
    show_default=True,
    help="Hostname to listen on.",
)
@click.option(
    "--port",
    type=int,
    default=5000,
    show_default=True,
    help="Port of the webserver.",
)
@click.option("--debug", is_flag=True, default=False, help="Enable debug mode.")
@click.option(
    "--proxy",
    is_flag=True,
    default=False,
    help="Use when the server sits behind a reverse proxy.",
)
@click.option(
    "--api-prefix",
    type=str,
    default="",
    show_default=True,
    help="Deployment (reverse-proxy) prefix prepended before /api/v1/... "
         "in generated endpoint URLs (e.g. '/plantdb'). "
         "The API version prefix /api/v1 is always included.",
)
@optgroup.group("Database", cls=OptionGroup)
@optgroup.option(
    "-db",
    "--db-path",
    type=click.Path(),
    default=os.getenv("ROMI_DB", None),
    show_default=True,
    help="Path to the local database to serve.",
)
@optgroup.option(
    "--test",
    is_flag=True,
    default=False,
    help="Set up a temporary test database before starting the REST API.",
)
@optgroup.option(
    "--empty",
    is_flag=True,
    default=False,
    help="Do not populate the test database with toy datasets.",
)
@optgroup.option(
    "--models",
    is_flag=True,
    default=False,
    help="Include trained CNN model in the test database.",
)
@optgroup.group("Logging", cls=OptionGroup)
@optgroup.option(
    "--log-level",
    type=click.Choice(LOG_LEVELS, case_sensitive=False),
    default=DEFAULT_LOG_LEVEL,
    show_default=True,
    help="Logging level.",
)
def main(host, port, debug, proxy, api_prefix, db_path, test, empty, models, log_level):
    """FSDB REST API - Serve Plant Database through RESTful Endpoints."""
    app = rest_api(db_path=db_path, proxy=proxy, deploy_prefix=api_prefix, log_level=log_level.upper(), test=test,
                   empty=empty, models=models)
    # Start the Flask development server.
    app.run(host=host, port=port, debug=debug)

rest_api Link

rest_api(db_path, proxy=False, api_prefix='', deploy_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 Link

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 Link

bool

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

False

api_prefix Link

str

Deprecated. Kept for backward compatibility; use deploy_prefix instead.

''

deploy_prefix Link

str

Deployment (reverse-proxy) prefix prepended before /api/v1/... when generating external-facing URLs in responses (e.g. /plantdb). Default is "" (no deployment prefix).

''

log_level Link

str

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

DEFAULT_LOG_LEVEL

test Link

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 Link

bool

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

False

models Link

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
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
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
523
524
525
526
def rest_api(
        db_path: Optional[Union[str, Path]],
        proxy: bool = False,
        api_prefix: str = "",
        deploy_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.
    api_prefix : str, optional
        **Deprecated.** Kept for backward compatibility; use ``deploy_prefix`` instead.
    deploy_prefix : str, optional
        Deployment (reverse-proxy) prefix prepended before ``/api/v1/...``
        when generating external-facing URLs in responses (e.g. ``/plantdb``).
        Default is ``""`` (no deployment prefix).
    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")
    # Get the logger and change the level if needed:
    logger = get_logger(os.environ.get('ROMI_APP_LOGGER', __name__))
    logger.setLevel(log_level)

    # Resolve deployment prefix: use explicit ``deploy_prefix``, else ``api_prefix`` (deprecated).
    _deploy_prefix = deploy_prefix or api_prefix or ""
    # 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, _deploy_prefix, logger)

    # 1b - Redirect the server root (``/``) to the API home endpoint.
    _register_root_redirect(app, _deploy_prefix)

    # 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' CLI argument."
        )
        sleep(1)
        sys.exit("Wrong database location!")

    # 4 - Database connection
    jwt_key = _get_env_secret("JWT_SECRET_KEY", logger)
    session_timeout = int(os.getenv("SESSION_TIMEOUT", 3600))
    refresh_timeout = int(os.getenv("REFRESH_TIMEOUT", 86400))
    max_sessions = int(os.getenv("MAX_SESSION", 10))
    db = FSDB(
        db_path,
        session_manager=JWTSessionManager(
            secret_key=jwt_key,
            session_timeout=session_timeout,
            refresh_timeout=refresh_timeout,
            max_concurrent_sessions=max_sessions,
        ),
        log_level=log_level,
    )
    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, deploy_prefix=_deploy_prefix)

    return app