コード例 #1
0
ファイル: rest.py プロジェクト: vvmruder/pyramid_rest
    def __init__(self, url, config, name):
        """
        A Object which holds the connection to the database and arbitrary numbers of services. It works like a proxy
        for the request. It decides which service will be finally called by reading the requested url parts and calls
        the appropriate service method.

        In addition you can implement api wide behaviour like authorization be subclassing this class and adding some
        pre or post processing to the particular methods.

        :param url: The connection string which is used to let the api connect with the desired database.
        It must have the form as described here:
        http://docs.sqlalchemy.org/en/latest/core/engines.html
        :type url: str
        :param config: The config of the hosting pyramid application.
        :type config: pyramid.config.Configurator
        :param name: The name which is used internally as an identifier of the api, to make it selectable between other
        api's. This name must be unique all over the application. If not an error will be thrown on application start
        up.
        :type name: str
        :raises: LookupError
        """
        connection_already_exists = False
        for key, value in config.registry.pyramid_rest_database_connections.iteritems():
            if url in key:
                connection_already_exists = True
                self.connection = value

        if not connection_already_exists:
            self.connection = Connection(url)
            config.registry.pyramid_rest_database_connections[url] = self.connection

        self.services = {}

        if name not in config.registry.pyramid_rest_apis:
            config.registry.pyramid_rest_apis[name] = self
        else:
            log.error(
                "The Api-Object you created seems to already exist in the registry. It has to be unique at all. "
                "Couldn't be added. Sorry..."
            )
            raise LookupError()
コード例 #2
0
ファイル: rest.py プロジェクト: vvmruder/pyramid_rest
class Api(object):

    def __init__(self, url, config, name):
        """
        A Object which holds the connection to the database and arbitrary numbers of services. It works like a proxy
        for the request. It decides which service will be finally called by reading the requested url parts and calls
        the appropriate service method.

        In addition you can implement api wide behaviour like authorization be subclassing this class and adding some
        pre or post processing to the particular methods.

        :param url: The connection string which is used to let the api connect with the desired database.
        It must have the form as described here:
        http://docs.sqlalchemy.org/en/latest/core/engines.html
        :type url: str
        :param config: The config of the hosting pyramid application.
        :type config: pyramid.config.Configurator
        :param name: The name which is used internally as an identifier of the api, to make it selectable between other
        api's. This name must be unique all over the application. If not an error will be thrown on application start
        up.
        :type name: str
        :raises: LookupError
        """
        connection_already_exists = False
        for key, value in config.registry.pyramid_rest_database_connections.iteritems():
            if url in key:
                connection_already_exists = True
                self.connection = value

        if not connection_already_exists:
            self.connection = Connection(url)
            config.registry.pyramid_rest_database_connections[url] = self.connection

        self.services = {}

        if name not in config.registry.pyramid_rest_apis:
            config.registry.pyramid_rest_apis[name] = self
        else:
            log.error(
                "The Api-Object you created seems to already exist in the registry. It has to be unique at all. "
                "Couldn't be added. Sorry..."
            )
            raise LookupError()

    def add_service(self, service):
        """
        Add's a service to the api.

        :param service: The service which should be added to the api.
        :type service: Service
        :raises: LookupError
        """
        if service.name not in self.services:
            self.services[service.name] = service
        else:
            log.error(
                "The Service {name} was defined for this API already. Use the defined one.".format(
                    name=service.name
                )
            )
            raise LookupError()

    def provide_session(self, request):
        """
        This method provides a usable SQLAlchemy session instance. It is ensured, that this session is doomed
        independent from the behavior of the request (it installs a finished listener to the request)


        :param request: The request of the pyramid web framework
        :type request: Request
        :return: a usable instance of a SQLAlchemy Session
        :rtype : Session
        """
        session_instance = self.connection.session()
        inner_scoped_session = self.connection.session

        def cleanup(request):
            if request.exception is None:
                transaction.commit()
            else:
                transaction.abort()
            inner_scoped_session.remove()

        request.add_finished_callback(cleanup)

        return session_instance

    def find_service_by_definition(self, schema_name, table_name):
        """
        Little helper method to obtain a service from the api's service list by it's unique schema+table name
        combination.

        :param schema_name: str
        :param table_name: str
        :return: Service or None
        :rtype: Service
        """
        return self.services.get(Service.name_from_definition(schema_name, table_name))

    def find_service_by_request(self, request):
        """
        Little helper method to scrabble the requested service directly from the url which was requested.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: The service.
        :rtype: Service
        :raises: HTTPNotFound
        """
        schema_name = request.matchdict['schema_name']
        table_name = request.matchdict['table_name']
        service = self.find_service_by_definition(schema_name, table_name)
        if service is None:
            text = 'Service with schema {schema_name} and table {table_name} could not be found.'.format(
                schema_name=schema_name,
                table_name=table_name
            )
            log.error(text)
            raise HTTPNotFound(
                detail=text
            )
        return service

    def read(self, request):
        """
        The api wide method to receive the read request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).read(
            request,
            self.provide_session(request)
        )

    def show(self, request):
        """
        The api wide method to receive the show request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).show(
            request,
            self.provide_session(request)
        )

    def create(self, request):
        """
        The api wide method to receive the create request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).create(
            request,
            self.provide_session(request)
        )

    def delete(self, request):
        """
        The api wide method to receive the delete request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).delete(
            request,
            self.provide_session(request)
        )

    def update(self, request):
        """
        The api wide method to receive the update request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).update(
            request,
            self.provide_session(request)
        )

    def model(self, request):
        """
        The api wide method to receive the model request and passing it to the correct service. At this point it is
        possible to implement some post or pre processing by overwriting this method. The most common use case for this
        will be the implementation of an authorisation mechanism which has influence on the whole api. To have influence
        on special services please see the service class implementations read method.

        :param request: The request which comes all the way through the application from the client
        :type request: pyramid.request.Request
        :return: An pyramid response object
        :rtype: pyramid.response.Response
        """
        return self.find_service_by_request(request).model(
            request
        )