mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-10-30 23:47:30 +03:00 
			
		
		
		
	Merge 163dfb86fb into f02ea337a2
				
					
				
			This commit is contained in:
		
						commit
						42bec78b41
					
				|  | @ -91,3 +91,21 @@ decorator: | ||||||
|         # ... |         # ... | ||||||
|         path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))), |         path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))), | ||||||
|     ] |     ] | ||||||
|  | 
 | ||||||
|  | Logging Errors | ||||||
|  | -------------- | ||||||
|  | 
 | ||||||
|  | By default, when there is a GraphQL error because of client inputs , Django logs a very simple message | ||||||
|  | with 4xx HTTP status code. If you would like to see more details, you can enable | ||||||
|  | ``ClientErrorLogMiddleware`` as follows: | ||||||
|  | 
 | ||||||
|  | .. code:: python | ||||||
|  | 
 | ||||||
|  |     # settings.py | ||||||
|  | 
 | ||||||
|  |     MIDDLEWARE = [ | ||||||
|  |         "graphene_django.middlewares.ClientErrorLogMiddleware", | ||||||
|  |         # ... | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  | This middleware works when your endpoint is ``/graphql``. | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								graphene_django/middlewares.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								graphene_django/middlewares.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | import json | ||||||
|  | import logging | ||||||
|  | 
 | ||||||
|  | from django.utils.log import log_response | ||||||
|  | 
 | ||||||
|  | logger = logging.getLogger("django.graphene") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ClientErrorLogMiddleware: | ||||||
|  |     """ | ||||||
|  |     Logs graphql requests 4xx errors. (Except 401, 403) | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, get_response): | ||||||
|  |         self.get_response = get_response | ||||||
|  | 
 | ||||||
|  |     def __call__(self, request): | ||||||
|  |         response = self.get_response(request) | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             if ( | ||||||
|  |                 400 <= response.status_code < 500 | ||||||
|  |                 and response.status_code not in (401, 403) | ||||||
|  |                 and "graphql" in request.path.lower() | ||||||
|  |             ): | ||||||
|  |                 response_json = json.loads(response.content) | ||||||
|  | 
 | ||||||
|  |                 if "errors" in response_json: | ||||||
|  |                     log_response( | ||||||
|  |                         message=( | ||||||
|  |                             f"Graphql Error: {response_json['errors']}\n" | ||||||
|  |                             f"The Query is: {json.loads(request.body)}" | ||||||
|  |                         ), | ||||||
|  |                         response=response, | ||||||
|  |                     ) | ||||||
|  |         except Exception: | ||||||
|  |             logger.error(f"Error logging graphql error.", exc_info=True) | ||||||
|  | 
 | ||||||
|  |         return response | ||||||
							
								
								
									
										107
									
								
								graphene_django/tests/test_middlewares.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								graphene_django/tests/test_middlewares.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | ||||||
|  | import json | ||||||
|  | import logging | ||||||
|  | import graphene | ||||||
|  | import mock | ||||||
|  | from django.http.response import HttpResponse | ||||||
|  | from django.test import RequestFactory | ||||||
|  | from graphene.test import Client | ||||||
|  | 
 | ||||||
|  | from .models import Reporter | ||||||
|  | from .. import DjangoObjectType | ||||||
|  | from ..middlewares import ClientErrorLogMiddleware | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ReporterType(DjangoObjectType): | ||||||
|  |     class Meta: | ||||||
|  |         model = Reporter | ||||||
|  |         fields = "__all__" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Query(graphene.ObjectType): | ||||||
|  |     reporter = graphene.Field(ReporterType) | ||||||
|  | 
 | ||||||
|  |     def resolve_reporter(self, info, **args): | ||||||
|  |         return Reporter.objects.first() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_should_log_error(caplog): | ||||||
|  |     Reporter.objects.create(last_name="ABA") | ||||||
|  | 
 | ||||||
|  |     invalid_query = """ | ||||||
|  |         query ReporterQuery { | ||||||
|  |           reporter { | ||||||
|  |             invalidAttrName  | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     schema = graphene.Schema(query=Query) | ||||||
|  |     client = Client(schema) | ||||||
|  |     response = client.execute(invalid_query) | ||||||
|  | 
 | ||||||
|  |     factory = RequestFactory() | ||||||
|  |     request = factory.post( | ||||||
|  |         "/graphql", data=json.dumps(invalid_query), content_type="application/json" | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     http_res = HttpResponse(json.dumps(response).encode(), status=400) | ||||||
|  | 
 | ||||||
|  |     get_response = mock.MagicMock() | ||||||
|  |     get_response.return_value = http_res | ||||||
|  | 
 | ||||||
|  |     middleware = ClientErrorLogMiddleware(get_response) | ||||||
|  |     middleware(request) | ||||||
|  | 
 | ||||||
|  |     assert len(caplog.records) == 1 | ||||||
|  |     assert caplog.records[0] != "WARNING" | ||||||
|  |     assert str(response["errors"]) in caplog.text | ||||||
|  |     assert invalid_query in caplog.text | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_should_not_log_success(caplog): | ||||||
|  |     Reporter.objects.create(last_name="ABA") | ||||||
|  | 
 | ||||||
|  |     valid_query = """ | ||||||
|  |         query ReporterQuery { | ||||||
|  |           reporter { | ||||||
|  |             lastName | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     schema = graphene.Schema(query=Query) | ||||||
|  |     client = Client(schema) | ||||||
|  |     response = client.execute(valid_query) | ||||||
|  | 
 | ||||||
|  |     factory = RequestFactory() | ||||||
|  |     request = factory.post( | ||||||
|  |         "/graphql", data=json.dumps(valid_query), content_type="application/json" | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     http_res = HttpResponse(json.dumps(response).encode(), status=200) | ||||||
|  | 
 | ||||||
|  |     get_response = mock.MagicMock() | ||||||
|  |     get_response.return_value = http_res | ||||||
|  | 
 | ||||||
|  |     middleware = ClientErrorLogMiddleware(get_response) | ||||||
|  |     middleware(request) | ||||||
|  | 
 | ||||||
|  |     assert len(caplog.records) == 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_should_not_log_non_graphql_error(caplog): | ||||||
|  |     factory = RequestFactory() | ||||||
|  |     request = factory.post( | ||||||
|  |         "/users", data=json.dumps({"name": "Mario"}), content_type="application/json" | ||||||
|  |     ) | ||||||
|  |     http_res = HttpResponse( | ||||||
|  |         json.dumps({"errors": ["Got to be Luigi"]}).encode(), status=400 | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     get_response = mock.MagicMock() | ||||||
|  |     get_response.return_value = http_res | ||||||
|  | 
 | ||||||
|  |     middleware = ClientErrorLogMiddleware(get_response) | ||||||
|  |     middleware(request) | ||||||
|  | 
 | ||||||
|  |     assert len(caplog.records) == 0 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user