mirror of
				https://github.com/HackSoftware/Django-Styleguide.git
				synced 2025-10-30 07:07:25 +03:00 
			
		
		
		
	Init some text about exceptions in services
This commit is contained in:
		
							parent
							
								
									c99d80b37a
								
							
						
					
					
						commit
						2495712b90
					
				
							
								
								
									
										57
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								README.md
									
									
									
									
									
								
							|  | @ -197,6 +197,63 @@ class Serializer(serializers.Serializer): | ||||||
| The implementation of `inline_serializer` can be found in `utils.py` in this repo. | The implementation of `inline_serializer` can be found in `utils.py` in this repo. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ## Exception Handling | ||||||
|  | 
 | ||||||
|  | ### Raising Exceptions in Services | ||||||
|  | Now we have a great separation between business logic and HTTP logic. The business logic lives in the services and the HTTP logic lives in the APIs. | ||||||
|  | 
 | ||||||
|  | In order to keep this separation of concerns our services must not use the `rest_framework.exception` classes because they are bounded with HTTP status codes.  | ||||||
|  | Our services must use: `native python exceptions`, `django.core.exceptions` or some custom business exceptions that we define. | ||||||
|  | 
 | ||||||
|  | Here is a good example of service that preforms some business validation and raise `django.core.exceptions.ValidationError` | ||||||
|  | ```python | ||||||
|  | from django.core.exceptions import ValidationError | ||||||
|  | 
 | ||||||
|  | def create_topic(*, name: str, course: Course) -> Topic: | ||||||
|  |     if Topic.objects.filter(course=course, name=name).exists(): | ||||||
|  |         raise ValidationError('Topic with this name already exists for this course!') | ||||||
|  | 
 | ||||||
|  |     topic = Topic.objects.create(name=name, course=course) | ||||||
|  | 
 | ||||||
|  |     return topic | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Handle Exceptions in APIs | ||||||
|  | In order to transform the exceptions raised in the services to a standard HTTP response you need to catch the exception and return proper HTTP response. | ||||||
|  | 
 | ||||||
|  | The best place to do this is in the `handle_exception` method of the `APIView`. There you can map your exception to DRF exception. | ||||||
|  | 
 | ||||||
|  | Here is an example: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | class CourseCreateApi(SomeAuthenticationMixin, APIView): | ||||||
|  |     expected_exceptions = { | ||||||
|  |         ValidationError: serializers.ValidationError, | ||||||
|  |         ValueError: serializers.ValidationError, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class InputSerializer(serializers.Serializer): | ||||||
|  |         ... | ||||||
|  | 
 | ||||||
|  |     def post(self, request): | ||||||
|  |         serializer = self.InputSerializer(data=request.data) | ||||||
|  |         serializer.is_valid(raise_exception=True) | ||||||
|  | 
 | ||||||
|  |         create_course(**serializer.validated_data) | ||||||
|  | 
 | ||||||
|  |         return Response(status=status.HTTP_201_CREATED) | ||||||
|  | 
 | ||||||
|  |     def handle_exception(self, exc): | ||||||
|  |         if isinstance(exc, tuple(self.expected_exceptions.keys())): | ||||||
|  |             drf_exception_class = self.expected_exceptions[exc.__class__] | ||||||
|  |             drf_exception = drf_exception_class() | ||||||
|  | 
 | ||||||
|  |             return super().handle_exception(drf_exception) | ||||||
|  | 
 | ||||||
|  |         return super().handle_exception(exc) | ||||||
|  | ``` | ||||||
|  | You can move this code to a mixin and use it in every API to prevent code duplication.  | ||||||
|  | 
 | ||||||
| ## Inspiration | ## Inspiration | ||||||
| 
 | 
 | ||||||
| The way we do Django is inspired by the following things: | The way we do Django is inspired by the following things: | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user