def bindResource(apiInstance, resourceInstance): FlaskUtil.validateFlaskApi(apiInstance) FlaskUtil.validateResourceInstance(resourceInstance) setResource( ReflectionHelper.getAttributeOrMethod( apiInstance.resource, getResourceType(resourceInstance).lower()), resourceInstance)
def handleControllerMethod(args, kwargs, contentType, resourceInstance, resourceInstanceMethod, requestHeaderClass, requestParamClass, requestClass, logRequest, muteStacktraceOnBusinessRuleException): requestBodyAsJson = {} if resourceInstanceMethod.__name__ in OpenApiManager.ABLE_TO_RECIEVE_BODY_LIST and requestClass: requestBodyAsJson = getRequestBodyAsJson(contentType, requestClass) if Serializer.requestBodyIsPresent(requestBodyAsJson): requestBodyAsJsonSerialized = Serializer.convertFromJsonToObject( requestBodyAsJson, requestClass) args = getArgsWithSerializerReturnAppended( args, requestBodyAsJsonSerialized) headers = FlaskUtil.addToKwargs(FlaskUtil.KW_HEADERS, requestHeaderClass, FlaskUtil.safellyGetHeaders(), kwargs) query = FlaskUtil.addToKwargs(FlaskUtil.KW_PARAMETERS, requestParamClass, FlaskUtil.safellyGetArgs(), kwargs) try: if resourceInstance.logRequest or logRequest: log.prettyJson( resourceInstanceMethod, '[CONTROLLER] Request', { 'headers': headers, # 'query': FlaskUtil.addToKwargs(FlaskUtil.KW_PARAMETERS, requestParamClass, FlaskUtil.safellyGetArgs(), kwargs), ###- safellyGetUrl() returns query param 'body': requestBodyAsJson }, condition=True, logLevel=log.INFO) except Exception as exception: log.failure(innerResourceInstanceMethod, 'Not possible to log request properly', exception) return validateAndReturnResponse( handleAdditionalResponseHeadersIfNeeded( resourceInstanceMethod(resourceInstance, *args[1:], **kwargs)))
def addGlobalsTo(apiInstance) : FlaskUtil.validateFlaskApi(apiInstance) apiInstance.globals = FlaskUtil.getGlobals() apiInstance.globals.api = apiInstance apiInstance.bindResource = FlaskManager.bindResource apiInstance.scheme = apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_SERVER_SCHEME) apiInstance.host = apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_SERVER_HOST) apiInstance.port = apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_SERVER_PORT) apiInstance.baseUrl = apiInstance.globals.getApiSetting(ConfigurationKeyConstant.API_SERVER_BASE_URL)
def getRequestBodyAsJson(contentType, requestClass): try: if OpenApiManager.DEFAULT_CONTENT_TYPE == contentType: requestBodyAsJson = FlaskUtil.safellyGetJson() elif OpenApiManager.MULTIPART_X_MIXED_REPLACE in contentType: requestBodyAsJson = FlaskUtil.safellyGetData() else: raise Exception(f'Content type "{contentType}" not implemented') except Exception as exception: raise GlobalException(message='Not possible to parse the request', logMessage=str(exception), status=HttpStatus.BAD_REQUEST) validateBodyAsJson(requestBodyAsJson, requestClass) return requestBodyAsJson
def getErrorMessage(clientResponse, exception=None): completeErrorMessage = f'{HttpClientConstant.ERROR_AT_CLIENT_CALL_MESSAGE}{c.DOT_SPACE}{HttpClientConstant.CLIENT_DID_NOT_SENT_ANY_MESSAGE}' errorMessage = HttpClientConstant.CLIENT_DID_NOT_SENT_ANY_MESSAGE possibleErrorMessage = None bodyAsJson = {} try : bodyAsJson = clientResponse.json() except Exception as innerException : bodyAsJsonException = FlaskUtil.safellyGetResponseJson(clientResponse) log.log(getErrorMessage, f'Invalid client response: {bodyAsJsonException}', exception=innerException) log.debug(getErrorMessage, f'Not possible to get error message from client response: {bodyAsJsonException}. Proceeding with value {bodyAsJson} by default', exception=innerException, muteStackTrace=True) try: if ObjectHelper.isNotNone(clientResponse): if ObjectHelper.isDictionary(bodyAsJson): possibleErrorMessage = bodyAsJson.get('message', bodyAsJson.get('error')).strip() if ObjectHelper.isList(bodyAsJson) and 0 < len(bodyAsJson): possibleErrorMessage = bodyAsJson[0].get('message', bodyAsJson[0].get('error')).strip() if ObjectHelper.isNotNone(possibleErrorMessage) and StringHelper.isNotBlank(possibleErrorMessage): errorMessage = f'{c.LOG_CAUSE}{possibleErrorMessage}' else: log.debug(getErrorMessage, f'Client response {FlaskUtil.safellyGetResponseJson(clientResponse)}') exceptionPortion = HttpClientConstant.ERROR_AT_CLIENT_CALL_MESSAGE if ObjectHelper.isNone(exception) or StringHelper.isBlank(exception) else str(exception) completeErrorMessage = f'{exceptionPortion}{c.DOT_SPACE}{errorMessage}' except Exception as exception: log.warning(getErrorMessage, f'Not possible to get error message. Returning {completeErrorMessage} by default', exception=exception) return completeErrorMessage
def getCompleteResponse(clientResponse, responseClass, produces, fallbackStatus=HttpStatus.INTERNAL_SERVER_ERROR): responseBody, responseHeaders, responseStatus = dict(), dict(), fallbackStatus responseHeaders = FlaskUtil.safellyGetResponseHeaders(clientResponse) responseBody = FlaskUtil.safellyGetResponseJson(clientResponse) try : responseStatus = HttpStatus.map(HttpStatus.NOT_FOUND if ObjectHelper.isNone(clientResponse.status_code) else clientResponse.status_code) except Exception as exception : responseStatus = HttpStatus.map(fallbackStatus) log.warning(getCompleteResponse, f'Not possible to get client response status. Returning {responseStatus} by default', exception=exception) responseHeaders = { **{HttpDomain.HeaderKey.CONTENT_TYPE: produces}, **responseHeaders } responseStatus = ConverterStatic.getValueOrDefault(responseStatus, HttpStatus.map(fallbackStatus)) if ObjectHelper.isNone(responseClass): return responseBody, responseHeaders, responseStatus return Serializer.convertFromJsonToObject(responseBody, responseClass), responseHeaders, responseStatus
def __init__(self, *args, **kwargs): log.wrapper( OuterClass, f'in {InnerClass.__name__}.__init__(*{args},**{kwargs})', None) apiInstance = FlaskUtil.getApi() OuterClass.__init__(self) FlaskUtil.Resource.__init__(self, *args, **kwargs) self.service = apiInstance.resource.service self.globals = apiInstance.globals
def getAndPersistGlobalException(exception, resourceInstance, resourceInstanceMethod, apiInstance=None, context=HttpDomain.CONTROLLER_CONTEXT): return ExceptionHandler.handleLogErrorException( exception, resourceInstance, resourceInstanceMethod, context, apiInstance=apiInstance if ObjectHelper.isNotNone(apiInstance) else FlaskUtil.getNullableApi())
def getDefaultBodyException(exception=None): try: bodyErrorResponse = { 'message': exception.message, 'timestamp': str(exception.timeStamp) } except: bodyErrorResponse = { 'message': DEFAULT_MESSAGE, 'timestamp': str(DateTimeHelper.now()) } uriIfAny = FlaskUtil.safellyGetPath() if ObjectHelper.isNotNone(uriIfAny) and StringHelper.isNotBlank(uriIfAny): bodyErrorResponse['uri'] = uriIfAny return bodyErrorResponse
def raiseException(clientResponse, exception): raise GlobalException( logMessage = getErrorMessage(clientResponse, exception=exception), url = FlaskUtil.safellyGetRequestUrlFromResponse(clientResponse), status = FlaskUtil.safellyGetResponseStatus(clientResponse), logHeaders = { 'requestHeaders': FlaskUtil.safellyGetRequestHeadersFromResponse(clientResponse), 'responseHeaders': FlaskUtil.safellyGetResponseHeaders(clientResponse) }, logPayload = { 'requestBody': FlaskUtil.safellyGetRequestJsonFromResponse(clientResponse), 'responseBody': FlaskUtil.safellyGetResponseJson(clientResponse) }, context = HttpDomain.CLIENT_CONTEXT )
def runApi(*args, api=None, **kwargs): if ObjectHelper.isNone(api): api = FlaskUtil.getApi() muteLogs(api) if 'host' not in kwargs and api.host: kwargs['host'] = api.host if not 'localhost' == api.host else '0.0.0.0' if 'port' not in kwargs and api.port: kwargs['port'] = api.port apiUrl = getApiUrl(api) documentationUrl = OpenApiManager.getDocumentationUrl(api) healthCheckUrl = f'{documentationUrl[:-len(OpenApiManager.DOCUMENTATION_ENDPOINT)]}{HealthCheckConstant.URI}' log.success(runApi, f'Api will run at {apiUrl}') log.success(runApi, f'Health check will be available at {healthCheckUrl}') log.success(runApi, f'Documentation will be available at {documentationUrl}') api.app.run(*args, **kwargs) SessionManager.onShutdown(api, api.app) ApiKeyManager.onShutdown(api, api.app) SecurityManager.onShutdown(api, api.app) SchedulerManager.onShutdown(api, api.app) SqlAlchemyProxy.onShutdown(api, api.app) log.success(runApi, f'{api.globals.apiName} successfully shutdown')
def innerResourceInstanceMethod(*args, **kwargs): f'''(*args, {FlaskUtil.KW_HEADERS}={{}}, {FlaskUtil.KW_PARAMETERS}={{}}, **kwargs)''' # r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # r.headers["Pragma"] = "no-cache" # r.headers["Expires"] = "0" # r.headers['Cache-Control'] = 'public, max-age=0' resourceInstance = args[0] completeResponse = None log.info( resourceInstanceMethod, f'[CONTROLLER] {FlaskUtil.safellyGetVerb()} - {FlaskUtil.safellyGetUrl()}' ) try: completeResponse = handleAnyControllerMethodRequest( args, kwargs, consumes, resourceInstance, resourceInstanceMethod, contextRequired, apiKeyRequired, roleRequired, requestHeaderClass, requestParamClass, requestClass, logRequest, muteStacktraceOnBusinessRuleException) validateCompleteResponse(responseClass, completeResponse) except Exception as exception: log.log( innerResourceInstanceMethod, 'Failure at controller method execution. Getting complete response as exception', exception=exception, muteStackTrace=True) completeResponse = getCompleteResponseByException( exception, resourceInstance, resourceInstanceMethod, muteStacktraceOnBusinessRuleException) ###- request.method: GET ###- request.url: http://127.0.0.1:5000/alert/dingding/test?x=y ###- request.base_url: http://127.0.0.1:5000/alert/dingding/test ###- request.url_charset: utf-8 ###- request.url_root: http://127.0.0.1:5000/ ###- str(request.url_rule): /alert/dingding/test ###- request.host_url: http://127.0.0.1:5000/ ###- request.host: 127.0.0.1:5000 ###- request.script_root: ###- request.path: /alert/dingding/test ###- request.full_path: /alert/dingding/test?x=y ###- request.args: ImmutableMultiDict([('x', 'y')]) ###- request.args.get('x'): y try: status = HttpStatus.map(completeResponse[-1]) additionalResponseHeaders = completeResponse[1] if ObjectHelper.isNotNone(resourceInstance.responseHeaders): additionalResponseHeaders = { **resourceInstance.responseHeaders, **additionalResponseHeaders } if ObjectHelper.isNotNone(responseHeaders): additionalResponseHeaders = { **responseHeaders, **additionalResponseHeaders } responseBody = completeResponse[0] if ObjectHelper.isNotNone( completeResponse[0]) else { 'message': status.enumName } httpResponse = FlaskUtil.buildHttpResponse( additionalResponseHeaders, responseBody, status.enumValue, produces) except Exception as exception: log.failure( innerResourceInstanceMethod, f'Failure while parsing complete response: {completeResponse}. Returning simplified version of it', exception, muteStackTrace=True) completeResponse = getCompleteResponseByException( Exception('Not possible to handle complete response'), resourceInstance, resourceInstanceMethod, muteStacktraceOnBusinessRuleException) httpResponse = FlaskUtil.buildHttpResponse( completeResponse[1], completeResponse[0], completeResponse[-1].enumValue, produces) try: if resourceInstance.logResponse or logResponse: log.prettyJson( resourceInstanceMethod, '[CONTROLLER] Response', { 'headers': FlaskUtil.safellyGetResponseHeaders(httpResponse), 'body': FlaskUtil.safellyGetFlaskResponseJson( httpResponse ), ###- json.loads(Serializer.jsonifyIt(responseBody)) 'status': status }, condition=True, logLevel=log.INFO) except Exception as exception: log.failure(innerResourceInstanceMethod, 'Not possible to log response properly', exception) return httpResponse
def raiseExceptionIfNeeded(clientResponse): status = FlaskUtil.safellyGetResponseStatus(clientResponse) ###- clientResponse.status_code if ObjectHelper.isNone(status) or 500 <= status: raise GlobalException( logMessage = getErrorMessage(clientResponse), url = FlaskUtil.safellyGetRequestUrlFromResponse(clientResponse), status = status, logHeaders = { 'requestHeaders': FlaskUtil.safellyGetRequestHeadersFromResponse(clientResponse), 'responseHeaders': FlaskUtil.safellyGetResponseHeaders(clientResponse) }, logPayload = { 'requestBody': FlaskUtil.safellyGetRequestJsonFromResponse(clientResponse), 'responseBody': FlaskUtil.safellyGetResponseJson(clientResponse) }, context = HttpDomain.CLIENT_CONTEXT ) elif 400 <= status: raise GlobalException( message = getErrorMessage(clientResponse), logMessage = HttpClientConstant.ERROR_AT_CLIENT_CALL_MESSAGE, url = FlaskUtil.safellyGetRequestUrlFromResponse(clientResponse), status = status, logHeaders = { 'requestHeaders': FlaskUtil.safellyGetRequestHeadersFromResponse(clientResponse), 'responseHeaders': FlaskUtil.safellyGetResponseHeaders(clientResponse) }, logPayload = { 'requestBody': FlaskUtil.safellyGetRequestJsonFromResponse(clientResponse), 'responseBody': FlaskUtil.safellyGetResponseJson(clientResponse) }, context = HttpDomain.CLIENT_CONTEXT )
def captureTokenFromRequestHeader(self): return FlaskUtil.safellyGetHeaders().get(self.headerName)
def retrieveApiInstance(apiInstance=None, arguments=None): apiInstance = FlaskUtil.retrieveApiInstance(apiInstance=apiInstance, arguments=arguments) if ObjectHelper.isNone(apiInstance.sessionManager): raise Exception('There is no session manager') return apiInstance
def getRequestUrl(self): return FlaskUtil.safellyGetUrl()
def getRequestHeaders(self): return FlaskUtil.safellyGetHeaders()
def getRequestVerb(self): return FlaskUtil.safellyGetVerb()
def getRequestBody(self): return FlaskUtil.safellyGetRequestBody()
def getGlobals(): return FlaskUtil.getGlobals()
def getApi(): return FlaskUtil.getApi()
def getNullableApi(): return FlaskUtil.getNullableApi()