Skip to content

test_rest_api

Test REST API Server ModuleLink

Provides a lightweight, thread-based Flask server that serves the PlantDB REST API for use in automated tests and development. By running the server in a separate daemon thread, test suites can interact with a fully functional API without blocking the main interpreter, enabling fast, isolated integration tests.

Key FeaturesLink

  • Threaded server: Starts a WSGI server in a background thread that can be started and stopped programmatically.
  • Configurable environment: Host, port, URL prefix, SSL, and database initialization (test, empty, models) are all selectable via constructor arguments.
  • Context-manager support: Use with statements to automatically start and stop the server, ensuring clean teardown.
  • Convenient factory function: test_rest_api() creates a ready-to-use TestRestApiServer instance with a single call.

Usage ExamplesLink

>>> from plantdb.commons.test_database import test_database
>>> from plantdb.server.test_rest_api import test_rest_api
>>> from plantdb.server.test_rest_api import API_PREFIX
>>> # Create a test database
>>> db = test_database(dataset=None)
>>> # Create and start a REST API server
>>> api = test_rest_api(db.path(), port=5000)
>>> api.start()
>>> # Interact with the API (e.g., list scans)
>>> import requests
>>> response = requests.get(f"{api.get_base_url()}/{API_PREFIX}/scans")
>>> print(response.json())
['arabidopsis000', 'real_plant', 'real_plant_analyzed', 'virtual_plant', 'virtual_plant_analyzed']
>>> api.stop()

>>> # Using the server as a context manager
>>> with test_rest_api() as api:
...     print(f"API running at {api.get_base_url()}")
...     # Perform HTTP requests here

TestRestApiServer Link

TestRestApiServer(db_path=None, port=5000, host='127.0.0.1', deploy_prefix='', ssl=False, test=False, empty=False, models=False, logger=None)

A test REST API server that runs in a separate thread for testing purposes.

This class creates a Flask application that serves a PlantDB REST API and runs it in a separate thread so it doesn't block the current interpreter.

Attributes:

Name Type Description
db_path Path

Path to the database directory

port int

Port number for the server

host str

Host address for the server

deploy_prefix str

Deployment (reverse-proxy) prefix for external URL generation (default "").

mount_prefix str

Internal mount prefix (always '/api/v1').

ssl bool

Whether to use SSL/HTTPS

test bool

Whether to run in test mode, that is to populate with the test dataset (default: False)

empty bool

Whether to create an empty database (default: False)

models bool

Whether to create a database with models (default: False)

app Flask

Flask application instance

server BaseWSGIServer

WSGI server instance

thread Thread

Thread running the server

Examples:

>>> import requests
>>> from plantdb.server.test_rest_api import TestRestApiServer
>>> # EXAMPLE 1 - Create a test database and start the Flask App serving a REST API
>>> server = TestRestApiServer(test=True)
>>> server.start()
>>> # Get a list of all datasets from the DB:
>>> response = requests.get("http://127.0.0.1:5000/api/v1/scans")
>>> scans_list = response.json()
>>> print(scans_list)
['arabidopsis000', 'real_plant', 'real_plant_analyzed', 'virtual_plant', 'virtual_plant_analyzed']
>>> server.stop()
>>> # EXAMPLE 2 - Serve an existing database
>>> from plantdb.commons.test_database import test_database
>>> test_db = test_database()  # set up a temporary test database
>>> print(test_db.path())
/tmp/ROMI_DB_...
>>> server = TestRestApiServer(db_path=test_db.path())
>>> server.start()
>>> # Get a list of all datasets from the DB:
>>> response = requests.get("http://127.0.0.1:5000/api/v1/scans")
>>> scans_list = response.json()
>>> print(scans_list)
['real_plant_analyzed']
>>> server.stop()

Initialize the test REST API server.

Parameters:

Name Type Description Default

db_path Link

str or Path

Path to the database directory to serve

None

port Link

int

Port number for the server (default: 5000)

5000

host Link

str

Host address for the server (default: '127.0.0.1')

'127.0.0.1'

deploy_prefix Link

str

Deployment (reverse-proxy) prefix for external URL generation (default '').

''

ssl Link

bool

Whether to use SSL/HTTPS (default: False)

False

test Link

bool

Whether to run in test mode, that is to populate with the test dataset (default: False)

False

empty Link

bool

Whether to create an empty database (default: False)

False

models Link

bool

Whether to create a database with models (default: False)

False

logger Link

logger

A logger instance to use. By default, the logger will be set to the root logger.

None
Source code in plantdb/server/test_rest_api.py
118
119
120
121
122
123
124
125
126
127
128
129
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
166
167
168
169
170
def __init__(
    self,
    db_path=None,
    port=5000,
    host="127.0.0.1",
    deploy_prefix="",
    ssl=False,
    test=False,
    empty=False,
    models=False,
    logger=None,
):
    """Initialize the test REST API server.

    Parameters
    ----------
    db_path : str or pathlib.Path, optional
        Path to the database directory to serve
    port : int, optional
        Port number for the server (default: 5000)
    host : str, optional
        Host address for the server (default: '127.0.0.1')
    deploy_prefix : str, optional
        Deployment (reverse-proxy) prefix for external URL generation (default '').
    ssl : bool, optional
        Whether to use SSL/HTTPS (default: False)
    test : bool, optional
        Whether to run in test mode, that is to populate with the test dataset (default: False)
    empty : bool, optional
        Whether to create an empty database (default: False)
    models : bool, optional
        Whether to create a database with models (default: False)
    logger : logging.logger, optional
        A logger instance to use. By default, the logger will be set to the root logger.
    """
    self.db_path: Path = Path(db_path) if db_path else _mkdtemp_romidb()
    self.port: int = port
    self.host: str = host
    self.deploy_prefix: str = deploy_prefix
    self.mount_prefix: str = API_PREFIX  # always /api/v1
    self.ssl: bool = ssl
    self.test: bool = test
    self.empty: bool = empty
    self.models: bool = models
    self.app = None
    self.server = None
    self.thread = None
    self.logger: logging.Logger = (
        logger
        if logger
        else get_logger(self.__class__.__name__) or get_logger(__name__)
    )
    self._setup_flask_app()

prefix property Link

prefix

Backward-compatible alias: returns the deploy prefix.

__enter__ Link

__enter__()

Context manager entry.

Source code in plantdb/server/test_rest_api.py
264
265
266
267
def __enter__(self):
    """Context manager entry."""
    self.start()
    return self

__exit__ Link

__exit__(exc_type, exc_val, exc_tb)

Context manager exit.

Source code in plantdb/server/test_rest_api.py
269
270
271
def __exit__(self, exc_type, exc_val, exc_tb):
    """Context manager exit."""
    self.stop()

get_base_url Link

get_base_url()

Get the base URL for the API.

Returns:

Type Description
str

The base URL for the API.

Source code in plantdb/server/test_rest_api.py
238
239
240
241
242
243
244
245
246
247
def get_base_url(self):
    """Get the base URL for the API.

    Returns
    -------
    str
        The base URL for the API.
    """
    protocol = "https" if self.ssl else "http"
    return f"{protocol}://{self.host}:{self.port}"

get_server_config Link

get_server_config()

Get the server configuration settings.

Source code in plantdb/server/test_rest_api.py
249
250
251
252
253
254
255
256
257
def get_server_config(self):
    """Get the server configuration settings."""
    return {
        "host": self.host,
        "port": self.port,
        "deploy_prefix": self.deploy_prefix,
        "mount_prefix": self.mount_prefix,
        "ssl": self.ssl,
    }

is_running Link

is_running()

Check if the server is running.

Source code in plantdb/server/test_rest_api.py
234
235
236
def is_running(self):
    """Check if the server is running."""
    return self.thread is not None and self.thread.is_alive()

start Link

start()

Start the REST API server in a separate thread.

Source code in plantdb/server/test_rest_api.py
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
def start(self):
    """Start the REST API server in a separate thread."""
    if self.thread is not None and self.thread.is_alive():
        return  # Already running

    # Check if port is available
    if not self._is_port_available():
        raise RuntimeError(
            f"Port {self.port} is already in use on host {self.host}"
        )

    # Create server
    self.server = make_server(self.host, self.port, self.app, threaded=True)

    # Start a server in a separate thread
    self.thread = threading.Thread(target=self.server.serve_forever, daemon=True)
    self.thread.start()

    # Wait a bit for the server to start
    time.sleep(0.5)

    self.logger.info(f"Test REST API server started at {self.get_base_url()}")

stop Link

stop()

Stop the REST API server.

Source code in plantdb/server/test_rest_api.py
222
223
224
225
226
227
228
229
230
231
232
def stop(self):
    """Stop the REST API server."""
    if self.server:
        self.server.shutdown()
        self.server = None

    if self.thread and self.thread.is_alive():
        self.thread.join(timeout=5.0)
        self.thread = None

    self.logger.info("Test REST API server stopped")

test_rest_api Link

test_rest_api(db_path, port=5000, host='127.0.0.1', deploy_prefix='', ssl=False)

Create and return a TestRestApi instance.

This is a convenience function that creates a TestRestApi instance with the specified parameters. The returned instance can be used to start/stop a test REST API server.

Parameters:

Name Type Description Default

db_path Link

str or Path

The path to the database directory to serve

required

port Link

int

Port number for the server (default: 5000)

5000

host Link

str

Host address for the server (default: '127.0.0.1')

'127.0.0.1'

deploy_prefix Link

str

Deployment (reverse-proxy) prefix for external URLs (default '').

''

ssl Link

bool

Whether to use SSL/HTTPS (default: False)

False

Returns:

Type Description
TestRestApiServer

Configured TestRestApi instance

Examples:

>>> from plantdb.commons.test_database import test_database
>>> from plantdb.server.test_rest_api import test_rest_api
>>> # Create a test database
>>> db = test_database(dataset=None)
>>> # Create and start a REST API server
>>> api = test_rest_api(db.path(), port=5000)
>>> api.start()
INFO     [TestRestApiServer] Test REST API server started at http://127.0.0.1:5000
>>> # Use the API
>>> print(f"API running at: {api.get_base_url()}")
API running at: http://127.0.0.1:5000
>>> # Stop the server
>>> api.stop()
>>>
>>> # Or use as a context manager
>>> with test_rest_api(db.path(),port=5000) as api:
...     # API is running here
...     print(f"API URL: {api.get_base_url()}")
INFO     [TestRestApiServer] Test REST API server started at http://127.0.0.1:5000
API URL: http://127.0.0.1:5000
INFO     [TestRestApiServer] Test REST API server stopped
>>> # API is automatically stopped here
Source code in plantdb/server/test_rest_api.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
def test_rest_api(db_path, port=5000, host="127.0.0.1", deploy_prefix="", ssl=False):
    """Create and return a TestRestApi instance.

    This is a convenience function that creates a TestRestApi instance with the
    specified parameters. The returned instance can be used to start/stop a test REST API server.

    Parameters
    ----------
    db_path : str or pathlib.Path
        The path to the database directory to serve
    port : int, optional
        Port number for the server (default: 5000)
    host : str, optional
        Host address for the server (default: '127.0.0.1')
    deploy_prefix : str, optional
        Deployment (reverse-proxy) prefix for external URLs (default '').
    ssl : bool, optional
        Whether to use SSL/HTTPS (default: False)

    Returns
    -------
    plantdb.server.test_rest_api.TestRestApiServer
        Configured TestRestApi instance

    Examples
    --------
    >>> from plantdb.commons.test_database import test_database
    >>> from plantdb.server.test_rest_api import test_rest_api
    >>> # Create a test database
    >>> db = test_database(dataset=None)
    >>> # Create and start a REST API server
    >>> api = test_rest_api(db.path(), port=5000)
    >>> api.start()
    INFO     [TestRestApiServer] Test REST API server started at http://127.0.0.1:5000
    >>> # Use the API
    >>> print(f"API running at: {api.get_base_url()}")
    API running at: http://127.0.0.1:5000
    >>> # Stop the server
    >>> api.stop()
    >>>
    >>> # Or use as a context manager
    >>> with test_rest_api(db.path(),port=5000) as api:
    ...     # API is running here
    ...     print(f"API URL: {api.get_base_url()}")
    INFO     [TestRestApiServer] Test REST API server started at http://127.0.0.1:5000
    API URL: http://127.0.0.1:5000
    INFO     [TestRestApiServer] Test REST API server stopped
    >>> # API is automatically stopped here
    """
    return TestRestApiServer(db_path, port, host, deploy_prefix, ssl)