Python/Advanced

[Python] 데이터 직렬화 및 검증 라이브러리 비교 (with 웹프레임워크)

yubi5050 2024. 8. 4. 15:46

요약

아래 표를 기준으로 사용 환경, 타입 검사, 문서화 여부 등이 주된 기준 요소 일 것 같다.

제공되는 기능 자체는 동일해서, 라이브러리 사용 방식? 이 보다 편하게 느껴지는 것으로 선택하면 될 것 같다. 

 

  Pydantic DRF Marshmallow Cerberus Colander Voluptuous Attrs Schematics
릴리즈 날짜 2018년 1월 2011년 7월 2013년 5월 2014년 1월 2010년 6월 2012년 9월 2016년 4월 2013년 7월
사용 환경 FastAPI Django Flask
Chalice
일반 Python Pyramid 일반 Python
타입 검사 파이썬 
타입 힌팅
명시적 타입필드 명시적 필드 타입 명시적 필드 타입 명시적 필드 타입 명시적 필드 타입 파이썬 
타입 힌팅
명시적 필드 타입
유효성 검사 다양한 기본 제공 유효성 검사
커스텀 유효성 검사
(역)직렬화 Python 객체 <-> JSON
(자동)문서화 FastAPI 사용시
Swagger,
ReDoc
추가 라이브러리 설치
Swagger,
ReDoc
APISpec 과 통합하여 문서화 가능 문서화 도구와 별도 연동 필요
설정 및 사용 BaseModel 클래스 상속 Django 모델과 통합
ModelSerializer 클래스
Schema 클래스 상속 Validator 클래스를 상속 Schema 클래스를 상속 @attr.s 데코레이터 사용, attrs 클래스 사용 Schema 클래스를 상속
기타 특징 v2.0 Rust 로 성능 개선 러닝커브가
조금 있는편
러닝 커브 적당, 가장 심플 - - 추가 개발 x 클래스
편의성
-

 

 

Pydantic

사용 환경

  • FastAPI 및 파이썬 프레임워크

 

주요 기능

 

  • 타입 검사 : 파이썬의 Type Hinting 를 사용
  • 유효성 검사: 타입 힌팅을 통한 데이터 모델을 정의 및 유효성 검사
  • 직렬화/역직렬화: JSON 등의 데이터 형식으로 데이터를 변환 하고, 데이터의 타입을 강제하여 안정적인 처리 제공
  • 자동 문서화: 데이터 모델을 기반으로 API 문서를 자동 생성 가능 (Swagger UI, ReDoc).
  • 비동기 지원: 비동기 코드 지원 및 비동기 프레임 워크(FastAPI)에서도 사용될 수 있도록 설계, 높은 성능 제공
  • 공식 문서 : https://docs.pydantic.dev/latest/

 

예시 코드

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class MyModel(BaseModel):
    name: str
    age: int

@app.post("/items/")
async def create_item(item: MyModel): # <- 여기서 Schema 로 사용! (데이터 검증 등)
    return {"item": item}

 

DRF (Django Rest Framework)

사용 환경

  • Only Django

 

주요 기능

 

  • 통합성: Django 기반으로 Django 모델과 쉽게 연동 가능
  • 타입 검사 : 라이브러리의 명시적 필드 정의 (ex. IntegerField .. 등)
  • 유효성 검사: 필드별 유효성 검사 및 필드 타입/제약 조건 정의 가능 (serializers)
  • 직렬화 및 역직렬화: Python 객체 <-> JSON 등으로 직렬화/역직렬화 가능 (serializers)
  • APIView와 ViewSet: API 엔드포인트를 처리하는 다양한 클래스 제공 (views.py) 하여 엔드포인트를 보다 쉽게 만듬
  • 공식 문서 : https://www.django-rest-framework.org/

 

예시 코드

# myapp/models.py
from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

    def __str__(self):
        return self.name
        
        
# myapp/serializers.py
from rest_framework import serializers
from .models import MyModel

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = ('id', 'name', 'age')
        
        
# myapp/views.py
class MyModelListAPIView(APIView):
    def get(self, request):
        mymodels = MyModel.objects.all()
        serializer = MyModelSerializer(mymodels, many=True)
        return Response(serializer.data)
    
    
# myapp/urls.py
from django.urls import path
from .views import MyModelListAPIView

urlpatterns = [
    path('mymodels/', MyModelListAPIView.as_view(), name='mymodel-list'),
]

 

Marshmallow

 

 

사용 환경

  • Flask 및 기타 Python 프로젝트 (ex. lambda chalice)

 

주요 특징

  • 유연성: Flask와 같은 다양한 프레임워크에서 사용가능
  • 타입 검사 : 라이브러리의 명시적 필드 정의 (ex. IntegerField .. 등)
  • 직렬화 및 역직렬화: Python 객체 <-> JSON 등으로 직렬화/역직렬화 가능 (serializers)
  • 유효성 검사 : 데이터 필드의 유효성 검사 규칙 정의 및 검사
  • 데이터 스키마: 명시적으로 데이터 스키마를 정의하여 데이터의 구조와 타입을 검증합니다.
  • ORM 통합: Flask-SQLAlchemy와 같은 ORM과 통합하여 데이터베이스 모델을 직렬화/역직렬화 가능
  • 공식 문서 링크 : https://marshmallow.readthedocs.io/en/stable/index.html

 

예시 코드

# schemas.py
from marshmallow import Schema, fields, validates, ValidationError

class MyModelSchema(Schema):
    name = fields.Str(required=True)
    age = fields.Int(required=True)

    @validates('age')
    def validate_age(self, value):
        if value < 0:
            raise ValidationError('Age must be positive')
            
            
# app.py
from flask import Flask, request, jsonify
from marshmallow import ValidationError
from myapp.schemas import MyModelSchema
from myapp.models import MyModel

app = Flask(__name__)

# Routes
@app.route('/mymodels', methods=['GET'])
def get_mymodels():
    return my_models_schema.jsonify(my_models, many=True)

@app.route('/mymodels', methods=['POST'])
def add_mymodel():
    try:
    	# schema 정의대로 데이터 검증 하는 곳 !
        data = my_model_schema.load(request.json)
        new_mymodel = MyModel(**data)
        my_models.append(new_mymodel)
        return my_model_schema.jsonify(new_mymodel), 201
    except ValidationError as err:
        return jsonify(err.messages), 400

if __name__ == '__main__':
    app.run(debug=True)

 

 

Cerberus (케르베로스)

사용 환경

  • 일반 Python

 

주요 기능

  • 경량의 데이터 유효성 검증 라이브러리
  • JSON 및 Python 데이터 구조의 유효성을 검증하는 데 사용
  • 특정 규칙에 따라서 검사할 내용 작성 및 Validator 객체를 통한 검증
  • 10개월 전 마지막 커밋
  • 공식 문서 : https://docs.python-cerberus.org/

 

예시 코드

from cerberus import Validator

# 내가 검증할 schema에 대한 설명 작성
schema = {
    'name': {'type': 'string'},
    'age': {'type': 'integer', 'min': 18}
}
v = Validator(schema)

# Validator 객체에서 실제 데이터 검증
document = {'name': 'John', 'age': 30}
if v.validate(document):
    print("Valid document")
else:
    print("Invalid document:", v.errors)

 

Colander

사용 환경 

  • Pyramid 웹 프레임워크 (Colander 도 Pylons Project의 일환) 

 

 

주요 기능

import colander

class PersonSchema(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int(), validator=colander.Range(min=18))

schema = PersonSchema()
data = {'name': 'John', 'age': 30}
deserialized = schema.deserialize(data)
print(deserialized)

 

 

 

Voluptuous

사용 환경 

  • 일반 Python

 

주요 기능

 

 

from voluptuous import Schema, Required, All, Length, Range

schema = Schema({
    Required('name'): All(str, Length(min=1)),
    Required('age'): All(int, Range(min=18))
})

data = {'name': 'John', 'age': 30}
validated_data = schema(data)
print(validated_data)

 

 

Attrs

사용 환경 

  • 일반 Python

 

주요 기능

  • 파이썬에서 클래스를 보다 쉽게 정의하고 관리할 수 있도록 해주는 라이브러리
  • attrs는 반복적인 클래스 메소드(ex. __init__, __repr__, __eq__ 등)를 자동으로 생성해, 정의 단순화 및 코드 중복을 줄임
  • 라이브러리가 파이썬의 타입 힌트와 잘 통합 되어, 타입 검사를 자동으로 수행 가능
  • 타입 검사 : 파이썬 type hinting 을 통한 검증 (ex. validators.instance_of(int)
  • 클래스 정의를 단순화하고, 데이터 클래스의 유효성 검사 및 변환을 쉽게 만드는 라이브러리
  • 유효성 검사, 변환 기능 등
  • Github : https://github.com/python-attrs/attrs

 

import attr

@attr.s
class Person:
    name = attr.ib(validator=attr.validators.instance_of(str))
    age = attr.ib(validator=[attr.validators.instance_of(int), attr.validators.gt(17)])

person = Person(name='John', age=30)
print(person)

 

Schematics

사용 환경

  • 일반 Python

 

주요 기능

  • 타입 검사 : 라이브러리의 명시적 필드 정의 (ex. StringType, IntType 등 
  • 주요 기능: 모델 정의, 유효성 검사, 직렬화 및 역직렬화
  • 공식 문서 : https://schematics.readthedocs.io/en/latest/

 

from schematics.models import Model
from schematics.types import StringType, IntType
from schematics.exceptions import DataError

class Person(Model):
    name = StringType(required=True)
    age = IntType(required=True, min_value=18)

try:
    person = Person({'name': 'John', 'age': 30})
    person.validate()
    print(person.to_native())
except DataError as e:
    print(e.to_primitive())