Skip to content
Snippets Groups Projects
Commit ee8d45dd authored by Kin Jin Ng's avatar Kin Jin Ng
Browse files

Load router extensions modules

parent 82e9e86e
No related branches found
No related tags found
1 merge request!108Load router extensions modules
......@@ -183,6 +183,11 @@ class ConfigurationContainer:
default='300',
factory=lambda x: int(x))
extension_modules: EnvVar = EnvVar(
key='EXTENSION_MODULES',
description="""Comma separated list of extension module names to load.""",
default=None)
_environment_dict: Dict = os.environ
_contextual_loader: Callable = None
......
# Wellbore Domain Services Extensions
> :warning: **This is an alpha feature**
> Implementation changes are expected, and will not be announced.
[[_TOC_]]
## Use cases
### Include new routers
1. Add a new directory `<extension package name>/routers` under `app/extensions`
2. Add a new python module `<router module name>.py`
```
/wellbore-domain-services
- app
|- extensions
|- <extension package name>
|- __init__.py
|- routers
|- <router module name>.py
|- __init__.py
```
3. In `<router module name>.py` include the following global variables.
```python
from fastapi import APIRouter
router = APIRouter()
router_prefix = '<extension router prefix>'
router_tags = ['<extension router tags>']
```
4. Include new service endpoints to `router` in `<router module name>.py`.
- Use `@router.[get|post|delete|put|patch|...]` fastapi decorator to include new methods to the router
- Check WDMS routers implementation under `app/routers`
- The same pattern is encouraged to be used in the extension routers.
```python
from fastapi import APIRouter, Depends, status
from app.utils import Context, get_ctx
from app.model.model_curated import *
from app.clients.storage_service_client import get_storage_record_service
from app.model.model_utils import from_record
router = APIRouter() # From previous step
# E.g.: Including a GET method API
@router.get('/markers/{marker_id}',
response_model=marker,
summary="Get the marker using wks:marker:1.0.4 schema",
description="""Get the Marker object using its **id**.""",
operation_id="get_marker",
responses={status.HTTP_404_NOT_FOUND: {"description": "marker not found"}},
response_model_exclude_unset=True)
async def get_marker(
marker_id: str,
ctx: Context = Depends(get_ctx)
) -> marker:
storage_client = await get_storage_record_service(ctx)
marker_record = await storage_client.get_record(id=marker_id, data_partition_id=ctx.partition_id)
return from_record(marker, marker_record)
```
5. Include the full router module name in `EXTENSION_MODULES` environment variable
E.g.: `app.extensions.<extension package name>.routers.<router module name>`
6. Update the deployment scripts accordingly.
7. Run WDMS service, and check in the logs for the messages
```
Loading `app.extensions.<extension package>.routers.<router module>` extension
Done. `app.extensions.<extension package>.routers.<router module>` loaded
```
8. Verify the new API endpoints were added under the provided tag,
and with the given prefix. `https://{base_url}/api/os-wellbore-ddms/docs/{Tag}`
9. Include test
- Unit tests are to be placed under `tests/unit/extensions/<extension package name>`
- Integration tests are to be placed under `tests/integration/functional/extensions/<extension package name>`
#### Troubleshooting
##### A. Wrong router module configuration
Check step #3 above
```shell
Loading `app.extensions.{}.routers.{}` extension
Failed to load `app.extensions.{}.routers.{}` extension.
Module not configured properly. module 'app.extensions.{}.routers.{}' has no attribute 'router_prefix'
```
##### B. Wrong module name
Review steps #2 and #4 above
```shell
Loading `app.extensions.{}.routers.{}` extension
Failed to load `app.extensions.{}.routers.{}` extension.
Module not found.
No module named 'app.extensions.{}.routers.{}'
```
##### C. Trailing comma in `EXTENSION_MODULES` list
Review step #4 above, make sure there is no trailing comma in the `EXTENSION_MODULES` list.
```shell
Loading `` extension
Failed to load `` extension. Empty module name
```
......@@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from fastapi import FastAPI, Depends
from fastapi.openapi.utils import get_openapi
......@@ -42,6 +43,9 @@ from app.routers.search import search, fast_search
from app.clients import StorageRecordServiceClient, SearchServiceClient
from app.utils import get_http_client_session, OpenApiHandler, get_wdms_temp_dir
import importlib
base_app = FastAPI()
......@@ -189,3 +193,28 @@ wdms_app.add_middleware(CreateBasicContextMiddleware, injector=app_injector)
# adding exception handling
add_exception_handlers(wdms_app)
# Load extensions [alpha version]
discovered_extensions = []
extension_modules = Config.extension_modules.value
if extension_modules:
discovered_extensions = extension_modules.split(',')
for name in discovered_extensions:
try:
print(f'Loading `{name}` extension')
module = importlib.import_module(name)
wdms_app.include_router(module.router, prefix=module.router_prefix, tags=module.router_tags,
dependencies=[
Depends(require_data_partition_id, use_cache=False),
Depends(require_opendes_authorized_user, use_cache=False)])
print(f'\tDone. `{name}` loaded')
except AttributeError as error:
print(f'\tFailed to load `{name}` extension. Module not configured properly. {error}')
except ModuleNotFoundError as error:
print(f'\tFailed to load `{name}` extension. Module not found. {error}')
except ValueError as error:
print(f'\tFailed to load `{name}` extension. {error}')
except:
print(f'\tFailed to load `{name}` extension. {sys.exc_info()[0]}')
\ No newline at end of file
......@@ -23,6 +23,9 @@ data:
USE_PARTITION_SERVICE: {{ .Values.configMap.data.usePartitionService }}
AZ_LOGGER_LEVEL: {{ .Values.configMap.data.loggerLevel }}
ENVIRONMENT_NAME: {{ .Values.configMap.data.environmentName }}
{{ if .Values.configMap.data.extensionModules }}
EXTENSION_MODULES: {{ .Values.configMap.data.extensionModules }}
{{ end }}
kind: ConfigMap
metadata:
annotations:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment