コード例 #1
0
    def rest_api(
        self,
        encoding: Encoding = JsonEncoding(),
        validator: Validator = NoneValidator()
    ) -> Callable:
        """
        Decorator for API Gateway event.

        Automatically parse string if the 'body' can be parsed as Dictionary.
        Automatically returns 500 error if unexpected error happens.

        Parameters
        ----------
        response_headers: dict
            Response headers when 500 error get_app.

        Usage::
            >>> from jeffy.framework import setup
            >>> from jeffy.encoding.json import JsonEncoding
            >>> app = get_app()
            >>> @app.handlers.rest_api(encoding=JsonEncoding())
            ... def handler(event, context):
            ...     return event['body']['foo']
        """
        def _rest_api(func: Callable):  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                try:
                    self.capture_correlation_id(event)
                    if event.get('body') is not None:
                        try:
                            event['body'] = encoding.decode(
                                event.get('body', '').encode('utf-8'))
                            validator.validate(event['body'])
                        except (DecodeError, ValidationError) as e:
                            self.app.logger.exception(e)
                            return {
                                'statusCode': 400,
                                'headers': {
                                    self.app.correlation_id_header:
                                    self.app.correlation_id
                                },
                                'body': json.dumps({'error_message': str(e)})
                            }
                    self.app.logger.info(event)
                    ret = func(event, context)
                    if ret.get('headers') is not None:
                        ret['headers'].update({
                            self.app.correlation_id_header:
                            self.app.correlation_id
                        })
                    self.app.logger.info(ret)
                    return ret
                except Exception as e:
                    self.app.logger.exception(e)
                    raise e

            return wrapper

        return _rest_api
コード例 #2
0
ファイル: common.py プロジェクト: watanabe3tipapa/jeffy
    def common(self, validator: Validator = NoneValidator()) -> Callable:
        """
        Decorator for common event.

        Automatically logs payload of events and errors with the correlation ID.

        Usage::
            >>> from jeffy.framework import get_app
            >>> app = get_app()
            >>> @app.handlers.event_logging
            ... def handler(event, context):
            ...     return event['body']['foo']
        """
        def _common(func: Callable):  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                self.capture_correlation_id(event)
                try:
                    self.app.logger.info(event)
                    ret = func(event, context)
                    self.app.logger.info(ret)
                    return ret
                except Exception as e:
                    self.app.logger.exception(e)
                    raise e

            return wrapper

        return _common
コード例 #3
0
    def schedule(self, validator: Validator = NoneValidator()) -> Callable:
        """
        Decorator for scheduled events.

        Usage::
            >>> from jeffy.framework import get_app
            >>> app = get_app()
            >>> @app.handlers.schedule
            ... def handler(event, context):
            ...     return event['body']['foo']
        """
        def _schedule(func: Callable) -> Callable:  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                validator.validate(event)
                self.capture_correlation_id(event)
                try:
                    self.app.logger.info(event)
                    ret = func(event, context)
                    self.app.logger.info(ret)
                    return ret
                except Exception as e:
                    raise e

            return wrapper

        return _schedule
コード例 #4
0
    def dynamodb_streams(
        self, validator: Validator = NoneValidator()) -> Callable:
        """
        Decorator for Dynamodb streams event.

        Automatically divide 'Records' for making it easy to treat it
        inside main process of Lambda.

        Usage::
            >>> from jeffy.framework import get_app
            >>> app = get_app()
            >>> @app.handlers.dynamodb_streams
            ... def handler(event, context):
            ...     return event['body']['foo']
        """
        def _dynamodb_streams(func: Callable) -> Callable:  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                ret = []
                for record in event['Records']:
                    message = record['body']
                    validator.validate(message)
                    self.capture_correlation_id(message)
                    try:
                        ret.append(func(message, context))
                    except Exception as e:
                        self.app.logger.exception(e)
                        raise e
                return ret

            return wrapper

        return _dynamodb_streams
コード例 #5
0
    def s3(
        self,
        encoding: Encoding = BytesEncoding(),
        validator: Validator = NoneValidator()
    ) -> Callable:
        """
        Decorator for S3 event.

        Automatically parse object body stream to Lambda.

        Usage::
            >>> from jeffy.framework import setup
            >>> from jeffy.encoding.bytes import BytesEncoding
            >>> app = get_app()
            >>> @app.handlers.s3(encoding=BytesEncoding())
            ... def handler(event, context):
            ...     return event['body']
        """
        def _s3(func: Callable) -> Callable:  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                from jeffy.sdk.s3 import S3
                s3 = S3()
                ret = []
                for record in event['Records']:
                    bucket = record['s3']['bucket']['name']
                    key = urllib.parse.unquote_plus(
                        record['s3']['object']['key'])
                    try:
                        response = s3.get_resource().get_object(Bucket=bucket,
                                                                Key=key)
                        self.capture_correlation_id(
                            response.get('Metadata', {}))
                        body = encoding.decode(response['Body'].read())
                        validator.validate(body)
                        self.app.logger.info({
                            'key': key,
                            'bucket_name': bucket,
                            'metadata': response['Metadata']
                        })
                        result = func(
                            {
                                'key': key,
                                'bucket_name': bucket,
                                'body': body,
                                'metadata': response['Metadata']
                            }, context)
                        self.app.logger.info(result)
                        ret.append(result)
                    except Exception as e:
                        self.app.logger.exception(e)
                        raise e
                return ret

            return wrapper

        return _s3
コード例 #6
0
ファイル: streams.py プロジェクト: watanabe3tipapa/jeffy
    def kinesis_streams(
        self,
        encoding: Encoding = JsonEncoding(),
        validator: Validator = NoneValidator()
    ) -> Callable:
        """
        Decorator for Kinesis stream event.

        Automatically divide 'Records' for making it easy to treat it
        inside main process of Lambda.

        Usage::
            >>> from jeffy.framework import get_app
            >>> from jeffy.encoding.json import JsonEncoding
            >>> app = get_app()
            >>> @app.handlers.kinesis_streams(encoding=JsonEncoding())
            ... def handler(event, context):
            ...     return event['body']['foo']
        """
        def _kinesis_streams(func: Callable) -> Callable:  # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):  # type: ignore
                ret = []
                for record in event['Records']:
                    message = encoding.decode(
                        base64.b64decode(record['kinesis']['data']))
                    validator.validate(message)
                    self.capture_correlation_id(message)
                    try:
                        self.app.logger.info(message)
                        result = func(message, context)
                        self.app.logger.info(result)
                        ret.append(result)
                    except Exception as e:
                        self.app.logger.exception(e)
                        raise e
                return ret

            return wrapper

        return _kinesis_streams
コード例 #7
0
    def sqs_raw(
        self,
        encoding: Encoding = JsonEncoding(),
        validator: Validator = NoneValidator()
    ) -> Callable:
        """
        Decorator for sqs raw events (with all metadatas).

        Automatically divide 'Records' and pass the record to main process of Lambda.

        Usage::
            >>> from jeffy.framework import get_app
            >>> app = get_app()
            >>> @app.handlers.sqs_raw()
            ... def handler(event, context):
            ...     return event['body']
        """
        def _sqs_raw(func: Callable):     # type: ignore
            @functools.wraps(func)
            def wrapper(event, context):            # type: ignore
                ret = []
                for record in event['Records']:
                    message = encoding.decode(record['body'].encode('utf-8'))
                    validator.validate(message)
                    self.capture_correlation_id(message)
                    record['body'] = message
                    try:
                        self.app.logger.info(message)
                        result = func(record, context)
                        self.app.logger.info(event)
                        ret.append(result)
                    except Exception as e:
                        self.app.logger.exception(e)
                        raise e
                return ret
            return wrapper
        return _sqs_raw