Extensibility feature

Implement extensibility of published APIs with vendor specific features

This work is funded by the European Commission through the project ENVELOPE with Grant Agreement number 101139048.

Edited by Stavros-Anastasios Charismiadis

Merge request reports

Loading
+9 −0
Changes for services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ from service_apis import util

from ..core.discoveredapis import DiscoverApisOperations
from flask import Response, request, current_app
import json

discover_apis = DiscoverApisOperations()

@@ -54,7+55,7 @@

    :rtype: Union[DiscoveredAPIs, Tuple[DiscoveredAPIs, int], Tuple[DiscoveredAPIs, int, Dict[str, str]]
    """
    if request.is_json:
        comm_type = CommunicationType.from_dict(request.get_json()())  # noqa: E501
    if request.is_json:
        protocol = Protocol.from_dict(request.get_json()())  # noqa: E501
@@ -70,7+71,7 @@
    query_params = {"api_name":api_name, "api_version":api_version, "comm_type":comm_type, 
    "protocol":protocol, "aef_id":aef_id, "data_format":data_format, 
    "api_cat":api_cat, "supported_features":supported_features, "api_supported_features":api_supported_features}

    if supported_features is not None:
        supp_feat_dict = DiscoveredAPIs.return_supp_feat_dict(supported_features)
        if supp_feat_dict['VendSpecQueryParams']:
            for q_params in request.args:
                if "vend-spec" in q_params:
                    query_params[q_params] = json.loads(request.args[q_params])

    response = discover_apis.get_discoveredapis(api_invoker_id, query_params)
    return response
+25 −4
Changes for services/TS29222_CAPIF_Discover_Service_API/service_apis/core/discoveredapis.py: 25 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ from ..core.responses import internal_server_error, forbidden_error ,make_respon
from ..models.discovered_apis import DiscoveredAPIs
from ..util import serialize_clean_camel_case
from ..core.resources import Resource
import json


class DiscoverApisOperations(Resource):
@@ -23,13 +24,33 @@ class DiscoverApisOperations(Resource):

            my_params = []
            my_query = {}
            quey_params_name = {"api_name":"api_name", "api_version":"aef_profiles.0.versions.0.api_version", "comm_type":"aef_profiles.0.versions.0.resources.0.comm_type", 
            "protocol":"aef_profiles.0.protocol", "aef_id":"aef_profiles.0.aef_id", "data_format":"aef_profiles.0.data_format", 
            "api_cat":"service_api_category", "supported_features":"supported_features", "api_supported_features":"api_supp_feats"}
            # QPV = Query Parameter Value
            query_params_name = {
                "api_name": "api_name",
                "api_version": '{"aef_profiles": {"$elemMatch": {"versions" : {"$elemMatch": {"api_version": "QPV"}}}}}',
                "comm_type": '{"aef_profiles": {"$elemMatch": {"versions" : {"$elemMatch": {"resources": {"$elemMatch": {"comm_type":"QPV"}}}}}}}',
                "protocol": '{"aef_profiles": {"$elemMatch": {"protocol":"QPV"}}}',
                "aef_id": '{"aef_profiles": {"$elemMatch": {"aef_id":"QPV"}}}',
                "data_format": '{"aef_profiles": {"$elemMatch": {"data_format":"QPV"}}}',
                "api_cat": "service_api_category",
                "supported_features": "supported_features",
                "api_supported_features": "api_supp_feats"
            }

            for param in query_params:
                current_app.logger.info(query_params[param])
                if query_params[param] is not None:
                    my_params.append({quey_params_name[param]: query_params[param]})
                    if "vend-spec" in param:
                        current_app.logger.info("vend-spec in param")
                        attribute_path = query_params[param]["target"].split('/')
                        attribute = "aef_profiles.0." + attribute_path[1] + "." + attribute_path[2]
                        my_params.append({attribute: query_params[param]["value"]})
                    elif param in ["api_version", "comm_type", "protocol", "aef_id", "data_format"]:
                        current_app.logger.info(query_params_name[param])
                        current_app.logger.info(query_params_name[param].replace("QPV", query_params[param]))
                        my_params.append(json.loads(query_params_name[param].replace("QPV", query_params[param])))
                    else:
                        my_params.append({query_params_name[param]: query_params[param]})

            if my_params:
                my_query = {"$and": my_params}
+11 −0
Changes for services/TS29222_CAPIF_Discover_Service_API/service_apis/models/discovered_apis.py: 11 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -30,6 +30,17 @@ class DiscoveredAPIs(Model):

        self._service_api_descriptions = service_api_descriptions

    @classmethod
    def return_supp_feat_dict(cls, supp_feat):
        supp_feat_in_hex = int(supp_feat, 16)
        supp_feat_in_bin = bin(supp_feat_in_hex)[2:]

        return {
            "RNAA": True if supp_feat_in_bin[0] == "1" else False,
            "VendSpecQueryParams": True if supp_feat_in_bin[1] == "1" else False,
            "ApiSupportedFeatureQuery": True if supp_feat_in_bin[2] == "1" else False,
        }

    @classmethod
    def from_dict(cls, dikt) -> 'DiscoveredAPIs':
        """Returns the dict as a model
+13 −3
Changes for services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py: 13 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -76,15 +76,25 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501
    :rtype: Union[ServiceAPIDescription, Tuple[ServiceAPIDescription, int], Tuple[ServiceAPIDescription, int, Dict[str, str]]
    """
    current_app.logger.info("Publishing service")
    current_app.logger.info(request.content_type)

    supp_feat_dict = ServiceAPIDescription.return_supp_feat_dict(body['supportedFeatures'])

    vendor_specific = []
    if request.is_json:
        body = ServiceAPIDescription.from_dict(request.get_json())  # noqa: E501
        if supp_feat_dict['VendorExt']:
            aef_profile_array = body['aefProfiles']
            for (profile,i) in zip(aef_profile_array, range(len(aef_profile_array))):
                for key, val in profile.items():
                    if 'vendorSpecific' in key:
                        vendor_specific.append((i, key, val))

    res = service_operations.add_serviceapidescription(apf_id, body)
        body = ServiceAPIDescription.from_dict(request.get_json())

    res = service_operations.add_serviceapidescription(apf_id, body, vendor_specific)

    return res


@cert_validation()
def apf_id_service_apis_service_api_id_delete(service_api_id, apf_id):  # noqa: E501
    """apf_id_service_apis_service_api_id_delete
+10 −4
Changes for services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py: 10 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ from flask import current_app, Flask, Response

from .resources import Resource
from datetime import datetime
from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case
from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case,clean_n_camel_case
from .responses import internal_server_error, forbidden_error, not_found_error, unauthorized_error, make_response
from .auth_manager import AuthManager
from .redis_event import RedisEvent
@@ -78,7 +78,7 @@ class PublishServiceOperations(Resource):
            current_app.logger.error(exception + "::" + str(e))
            return internal_server_error(detail=exception, cause=str(e))

    def add_serviceapidescription(self, apf_id, serviceapidescription):
    def add_serviceapidescription(self, apf_id, serviceapidescription, vendor_specific):

        mycol = self.db.get_col_by_name(self.db.service_api_descriptions)

@@ -102,7 +102,13 @@ class PublishServiceOperations(Resource):
            rec = dict()
            rec['apf_id'] = apf_id
            rec['onboarding_date'] = datetime.now()
            rec.update(serviceapidescription.to_dict())
            serviceapidescription_dict = serviceapidescription.to_dict()
            if vendor_specific:
                for vend_spec in vendor_specific:
                    for (profile,i) in zip(serviceapidescription_dict['aef_profiles'], range(len(serviceapidescription_dict['aef_profiles']))):
                        if i == vend_spec[0]:
                            profile[vend_spec[1]] = vend_spec[2]
            rec.update(serviceapidescription_dict)

            mycol.insert_one(rec)

@@ -110,7 +116,7 @@ class PublishServiceOperations(Resource):

            current_app.logger.debug("Service inserted in database")

            res = make_response(object=serialize_clean_camel_case(serviceapidescription), status=201)
            res = make_response(object=clean_n_camel_case(serviceapidescription_dict), status=201)
            res.headers['Location'] = "http://localhost:8080/published-apis/v1/" + \
                          str(apf_id) + "/service-apis/" + str(api_id)

Loading
Loading