본문 바로가기

TIL

API 요청 모듈 계층 분리 과정

Meet-up-spot이라는 만남 장소 추천 웹애플리케이션 프로젝트를 혼자 진행한다고 정신이 없었는데, 정신이 없어서 그랬는지 프로젝트하면서 섣부르게 진행한 부분에서 수정할 부분을 발견했다. 

 

원래는 구글 maps api 요청을 직접 보내는 모듈을 작성해서 작업하고 있었는데, 보니까 애초에 라이브러리가 있더라. 아무리 그래도 너무  급하게 진행했던 거 같다.

근데 보면 라이브러리가 최근 api를 반영을 못해서 만약 사용한다고 해도 직접 요청 보내는 부분도 필요할거 같아 보였다.

사실 기능만 같으면 예전 것을 써도 되는데 테스트하는 과정에서 안 되는 게 있어서 일단 최근 api 테스트해보고 확정 지어야겠다.

그리고 이건 계속 사용하면서 불편했던 부분이기도 한데,  카카오 맵이 api가 더 간단해 보여서 바꿀까 생각도 들었다. 

 

아무튼 결론적으로는 라이브러리를 쓰는 게 깔끔하니 일단은 라이브러리에 맞게 기존 코드를 수정하면서 아직 정해지지 않은 부분을 감안해서 확장성 있게 구조를 가져가봐야겠다는 생각이 들었다.

이 작업을 진행하려고 할 때 현 상황에서 가장 우선순위로 뒀던 건 라이브러리를 쓰는 부분과 직접 외부 api요청 부분을 래핑 하는 하나의 계층을 만드는 것이었다.  그래서 처음 map_service로 있던 부분에서 바로 요청을 받는 게 아니라 어댑터를 하나 둬서 그 어댑터를 서비스에서 호출해서 사용하는 식으로 작성했다.

이름을 어댑터라 한건 나중에 다른 api를 생각하고 어댑터 패턴을 생각하고 작성하긴 했는데, 현재는 base 인터페이스를 구현하지도 않았고 다른 api서비스도 추가하지 않았다. 그래서 어댑터 패턴은 아니다. 그냥 wrapper다.

다만 내가 확장성을 가져간 부분은 map_service와 map_adpater를 나누고 거기서 생성자로 의존성을 주입하여 client를 다르게 가져가는 형태로 작성했다.  어차피 만약~~에 라도 카카오로 바꾸거나 추가하게 되면 client 부분만 현재 인터페이스에 맞게 작성하면 될 거 같아서 이런 식으로 구현했다. 

근데 여기서 client의 인터페이스를 구글 maps api와 맞추지 않고 base 어댑터 구현후 각각 상속해서 구현하면 위에서 처음 생각한 어댑터 패턴이 될텐데. 어차피 새로 추가될 client 인터페이스를 맞추는게 비용이 그렇게 들거 같진 않았다.

class MapAdapter:
    def __init__(self, client=None, db=None):
        self.client = client
        self.db = db

    def format_place_id(self, place_id):
        return f"place_id:{place_id}"

    def geocode_address(self, address):
        try:
            result = self.client.geocode(address)

            if not result:
                raise ZeroResultException("No geocoding results found")

            return result
        except Exception as e:
            raise CustomException(e)
       .......
            
    class MapServices:
        def __init__(self, map_client=None):
            if map_client is None:
                map_client = googlemaps.Client(key=settings.GOOGLE_MAPS_API_KEY)
            self.map_adapter = MapAdapter(map_client)
            
        def get_lat_lng_from_address(self, address: str) -> GeocodeResponse:
            results = self.map_adapter.geocode_address(address)

            if not results:
                raise ZeroResultException("No geocoding results found")

            location = results[0]["geometry"]["location"]
            return GeocodeResponse(latitude=location["lat"], longitude=location["lng"])
           ......

'TIL' 카테고리의 다른 글

Bulk Insertion과 ORM 최적화  (0) 2023.10.09
결합과 추상화  (0) 2023.09.30
TDD 3부  (0) 2022.06.12
TDD 2부  (0) 2022.06.01
객체지향의 사실과 오해 3~4장  (1) 2022.03.31