>  기사  >  백엔드 개발  >  Monite의 API 버전 관리

Monite의 API 버전 관리

WBOY
WBOY원래의
2024-08-29 20:30:31833검색

우리 모두는 멋진 새 도구를 갖고 싶어하지만 지속적으로 업데이트하는 일을 싫어합니다. 이는 운영 체제, 앱, API, Linux 패키지 등 모든 것에 적용됩니다. 업데이트로 인해 코드 작동이 중단되면 고통스럽고 업데이트가 시작되지도 않았을 때 고통은 두 배로 커집니다.

웹 API 개발에서는 새로운 업데이트가 있을 때마다 사용자 코드가 손상될 위험이 끊임없이 존재합니다. 귀하의 제품이 API라면 이러한 업데이트는 매번 끔찍할 것입니다. Monite의 주요 제품은 API와 화이트 라벨 SDK입니다. 우리는 API 우선 회사이므로 API를 안정적이고 사용하기 쉽게 유지하는 데 세심한 주의를 기울입니다. 따라서 변경 사항을 깨뜨리는 문제는 우리의 우선순위 목록의 최우선 순위에 가깝습니다.

일반적인 해결책은 클라이언트에게 지원 중단 경고를 표시하고 주요 변경 사항을 거의 릴리스하지 않는 것입니다. 갑자기 릴리스가 완료되는 데 몇 달이 걸릴 수 있으며 일부 기능은 다음 릴리스가 나올 때까지 숨겨지거나 병합되지 않은 상태로 유지되어야 합니다. 이로 인해 개발 속도가 느려지고 사용자는 몇 달에 한 번씩 통합을 업데이트해야 합니다.

릴리스를 더 빠르게 만들면 사용자가 통합을 너무 자주 업데이트해야 할 것입니다. 릴리스 간격을 늘리면 회사의 움직임이 느려집니다. 사용자에게 불편함을 더 많이 줄수록 사용자에게는 더 편리해지며, 그 반대도 마찬가지입니다. 이는 확실히 최적의 시나리오는 아닙니다. 우리는 정기적인 지원 중단 접근 방식으로는 불가능할 기존 클라이언트의 어떤 것도 손상시키지 않고 우리 자신의 속도로 움직이고 싶었습니다. 이것이 우리가 대안 솔루션인 API 버전 관리를 선택한 이유입니다.

아주 간단한 아이디어입니다. 주요 변경 사항은 언제든지 공개하되 새 API 버전에서 숨기면 됩니다. 이는 두 세계의 장점을 모두 제공합니다. 사용자는 통합이 일상적으로 중단되지 않으며 원하는 속도로 이동할 수 있습니다. 사용자는 원할 때 언제든지 부담 없이 마이그레이션할 수 있습니다.

아이디어의 단순함을 고려하면 어느 회사에나 딱 맞는 느낌입니다. 이것이 일반적인 엔지니어링 블로그에서 읽을 것으로 예상되는 내용입니다. 안타깝게도 그렇게 간단하지는 않습니다.

가격을 조심하세요

API 버전 관리는 매우 어렵습니다. 환상적 단순성은 일단 구현을 시작하면 빠르게 사라집니다. 안타깝게도 해당 주제에 대한 리소스가 놀라울 정도로 적기 때문에 인터넷에서는 실제로 경고하지 않습니다. 그들 중 대다수는 API 버전을 어디에 둘 것인지에 대해 논쟁을 벌이고 있지만, "어떻게 구현합니까?"라는 질문에 대답하려는 기사는 거의 없습니다. 가장 일반적인 것은 다음과 같습니다.

  • 동일한 웹 애플리케이션의 여러 버전을 별도의 배포에 배치
  • 버전 간에 변경된 단일 경로 복사
  • 버전별 전체 애플리케이션 복사

개별 배포는 비용이 많이 들고 지원하기 어려울 수 있습니다. 단일 경로를 복사하면 큰 변경 사항에 맞게 확장되지 않으며, 전체 애플리케이션을 복사하면 너무 많은 추가 코드가 생성되어 몇 버전만 사용해도 빠져들게 됩니다.

가장 저렴한 것을 고르려고 해도 버전 관리에 대한 부담이 금방 따라잡을 것입니다. 처음에는 간단하게 느껴질 것입니다. 여기에 또 다른 스키마를 추가하고, 거기에 비즈니스 로직의 또 다른 분기를 추가하고, 마지막에 몇 개의 경로를 복제합니다. 그러나 버전이 충분하면 비즈니스 로직을 관리할 수 없게 되고, 많은 개발자가 애플리케이션 버전과 API 버전을 혼동하고, 데이터베이스 내의 데이터 버전 관리를 시작하게 되어 애플리케이션을 유지 관리할 수 없게 됩니다.

동시에 2~3개 이상의 API 버전을 사용하지 않기를 바랄 수도 있습니다. 몇 달에 한 번씩 이전 버전을 삭제할 수 있습니다. 소수의 내부 소비자만 지원하는 경우에는 그렇습니다. 하지만 조직 외부의 클라이언트는 몇 달에 한 번씩 업그레이드를 강요받는 경험을 즐기지 못할 것입니다.

API 버전 관리는 인프라에서 가장 비용이 많이 드는 부분 중 하나가 될 수 있으므로 사전에 부지런히 조사하는 것이 중요합니다. 내부 소비자만 지원한다면 GraphQL과 같은 것을 사용하는 것이 더 간단할 수 있지만 버전 관리만큼 비용이 빨리 들 수 있습니다.

스타트업이라면 API 버전 관리를 제대로 수행할 수 있는 리소스가 있을 때 개발 후반 단계까지 연기하는 것이 현명할 것입니다. 그때까지는 지원 중단 및 추가 변경 전략으로 충분할 수 있습니다. API가 항상 좋아 보이지는 않지만 적어도 명시적인 버전 관리를 피함으로써 상당한 비용을 절약할 수 있습니다.

API 버전 관리를 어떻게 구현합니까?

몇 번의 시행착오와 많은 오류 끝에 우리는 갈림길에 섰습니다. 위에서 언급한 이전 버전 관리 접근 방식은 유지 관리 비용이 너무 많이 들었습니다. 노력의 결과로 저는 완벽한 버전 관리 프레임워크에 필요한 다음 요구 사항 목록을 고안했습니다.

  1. "많은 수의 버전을 유지하는 것은 쉽습니다" 버전 관리로 인해 기능 개발 속도가 느려지지 않도록 합니다.
  2. "이전 버전을 삭제하는 것은 쉽습니다" 노력 없이 코드 베이스를 정리할 수 있습니다.
  3. "새 버전을 만드는 것은 그리 쉬운 일이 아닙니다". 이는 개발자가 버전 없이 문제를 해결하려고 노력할 수 있는 인센티브를 제공하기 위한 것입니다.
  4. "버전 간 변경 로그를 유지하는 것은 쉽습니다". 이를 통해 당사와 고객 모두 버전 간의 실제 차이점을 항상 확신할 수 있습니다

안타깝게도 기존 접근 방식에 대한 대안은 거의 또는 전혀 없었습니다. 이때 미친 아이디어가 떠올랐습니다. Stripe의 API 버전 관리와 같이 정교하고 작업에 완벽한 것을 구축해 보면 어떨까요?

수많은 실험의 결과로 이제 우리는 Stripe의 접근 방식을 구현할 뿐만 아니라 이를 기반으로 구축하는 오픈 소스 API 버전 관리 프레임워크인 Cadwyn을 갖게 되었습니다. Fastapi 및 Pydantic 구현에 대해 이야기할 예정이지만 핵심 원칙은 언어 및 프레임워크에 구애받지 않습니다.

캐드윈의 작동 방식

버전 변경

다른 모든 버전 관리 접근 방식의 문제는 너무 많이 복제된다는 것입니다. 계약의 아주 작은 부분만 깨졌는데 왜 전체 경로, 컨트롤러, 심지어 애플리케이션까지 복제하겠습니까?

Cadwyn을 사용하면 API 관리자가 새 버전을 생성해야 할 때마다 최신 스키마, 모델 및 비즈니스 로직에 주요 변경 사항을 적용할 수 있습니다. 그런 다음 새 버전과 이전 버전 간의 모든 차이점을 캡슐화하는 클래스인 버전 변경을 만듭니다.

예를 들어 이전에는 클라이언트가 하나의 주소로 사용자를 생성할 수 있었지만 이제는 단일 주소 대신 여러 주소를 지정할 수 있도록 허용하고 싶다고 가정해 보겠습니다. 버전 변경은 다음과 같습니다.

class ChangeUserAddressToAList(VersionChange):
    description = (
        "Renamed `User.address` to `User.addresses` and "
        "changed its type to an array of strings"
    )
    instructions_to_migrate_to_previous_version = (
        schema(User).field("addresses").didnt_exist,
        schema(User).field("address").existed_as(type=str),
    )

    @convert_request_to_next_version_for(UserCreateRequest)
    def change_address_to_multiple_items(request):
        request.body["addresses"] = [request.body.pop("address")]

    @convert_response_to_previous_version_for(UserResource)
    def change_addresses_to_single_item(response):
        response.body["address"] = response.body.pop("addresses")[0]

instructions_to_ migration_to_previous_version은 Cadwyn에서 이전 API 버전의 스키마에 대한 코드를 생성하는 데 사용되며 두 가지 변환기 기능은 우리가 원하는 만큼 많은 버전을 유지할 수 있게 해주는 비결입니다. 프로세스는 다음과 같습니다.

  1. Cadwyn은 Change_address_to_multiple_items 변환기를 사용하여 이전 API 버전의 모든 사용자 요청을 최신 API 버전으로 변환하고 이를 비즈니스 로직으로 파이프합니다.
  2. 비즈니스 로직, API 응답 및 데이터베이스 모델은 항상 최신 API 버전에 맞게 조정됩니다(물론 새 버전에 추가되더라도 이전 기능을 계속 지원해야 함).
  3. 비즈니스 로직이 응답을 생성한 후 Cadwyn은 Change_addresses_to_single_item 변환기를 사용하여 이를 클라이언트 요청자가 현재 사용 중인 이전 API 버전으로 변환합니다.

API 관리자가 버전 변경을 생성한 후 이를 VersionBundle에 추가하여 이 VersionChange가 일부 버전에 포함될 것임을 Cadwyn에 알려야 합니다.

VersionBundle(
    Version(
        date(2023, 4, 27),
        ChangeUserAddressToAList
    ),
    Version(
        date(2023, 4, 12),
        CollapseUserAvatarInfoIntoAnID,
        MakeUserSurnameRequired,
    ),
    Version(date(2023, 3, 15)),
)

그렇습니다. 획기적인 변경 사항을 추가했지만 비즈니스 로직은 단일 버전, 즉 최신 버전만 처리합니다. 수십 개의 API 버전을 추가한 후에도 비즈니스 로직에는 여전히 버전 관리 로직, 지속적인 이름 변경, if 및 데이터 변환기가 없습니다.

버전 체인화

버전 변경은 API의 공개 인터페이스에 따라 달라지며 기존 API 버전에 주요 변경 사항을 추가하는 경우는 거의 없습니다. 이는 일단 버전을 출시하면 버전이 깨지지 않는다는 것을 의미합니다.

버전 변경은 버전 내의 주요 변경 사항을 설명하고 이전 버전 내에서는 주요 변경 사항이 없기 때문에 버전 변경이 완전히 불변임을 확신할 수 있습니다. 즉, 변경할 이유가 전혀 없습니다. 불변 엔터티는 항상 진화하기 때문에 비즈니스 로직의 일부인 경우보다 유지 관리가 훨씬 쉽습니다. 버전 변경 사항도 차례로 적용됩니다. 즉, 모든 요청을 최신 버전으로 마이그레이션하고 모든 응답을 이전 버전으로 마이그레이션할 수 있는 버전 간에 변환기 체인을 형성합니다.

API Versioning at Monite

부작용

API 계약은 스키마와 필드보다 훨씬 더 복잡합니다. 이는 모든 엔드포인트, 상태 코드, 오류, 오류 메시지, 심지어 비즈니스 로직 동작까지 구성됩니다. Cadwyn은 위에서 설명한 것과 동일한 DSL을 사용하여 엔드포인트와 상태 코드를 처리하지만 오류와 비즈니스 로직 동작은 이야기가 다릅니다. DSL을 사용하여 설명하는 것은 불가능하며 비즈니스 로직에 포함되어야 합니다.

This makes such version changes much more expensive to maintain than all others because they affect business logic. We call this property a "side effect" and we try to avoid them at all costs because of their maintenance burden. All version changes that want to modify business logic will need to be marked as having side effects. It will serve as a way to know which version changes are "dangerous":

class RequireCompanyAttachedForPayment(VersionChangeWithSideEffects):
    description = (
        "User must now have a company_id in their account "
        "if they want to make new payments"
    )

It will also allow API maintainers to check that the client request uses an API version that includes this side effect:

if RequireCompanyToBeAttachedForPayment.is_applied:
    validate_company_id_is_attached(user)

No silver bullets

Cadwyn has many benefits: It greatly reduces the burden on our developers and can be integrated into our infrastructure to automatically generate the changelog and improve our API docs.

However, the burden of versioning still exists and even a sophisticated framework is not a silver bullet. We do our best to only use API versioning when absolutely necessary. We also try to make our API correct on the first try by having a special "API Council". All significant API changes are reviewed there by our best developers, testers, and tech writers before any implementation gets moving.

Special thanks to Brandur Leach for his API versioning article at Stripe and for the help he extended to me when I implemented Cadwyn: it would not be possible without his help.

위 내용은 Monite의 API 버전 관리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.