Подтвердить что ты не робот

Каковы ваши лучшие методы управления версиями WebService?

У нас есть 2 отдельных продукта, которые должны общаться друг с другом через веб-службы. Какова наилучшая практика для поддержки versioining API?

У меня эта статья от 2004 года, утверждая, что нет фактического стандарта и только лучшие практики. Какие-нибудь лучшие решения? Как вы решаете WS-версию?

Описание проблемы

Система A

Client

class SystemAClient{
    SystemBServiceStub systemB;
    public void consumeFromB(){
        SystemBObject bObject = systemB.getSomethingFromB(new SomethingFromBRequest("someKey"));

    }
}

Сервис

class SystemAService{
    public SystemAObject getSomethingFromA(SomethingFromARequest req){
        return new SystemAObjectFactory.getObject(req);
    }
}

Переносимый объект

Версия 1

class SystemAObject{
     Integer id;
     String name;
     ... // getters and setters etc;
}

Версия 2

class SystemAObject{
     Long id;
     String name;
     String description;
     ... // getters and setters etc;
}

Объект запроса

Версия 1

class SomethingFromARequest {
     Integer requestedId;
     ... // getters and setters etc;

}

Версия 2

class SomethingFromARequest {
     Long requestedId;
     ... // getters and setters etc;

}

Система B

Client

class SystemBClient{
    SystemAServiceStub systemA;
    public void consumeFromA(){
        SystemAObject aObject = systemA.getSomethingFromA(new SomethingFromARequest(1));
        aObject.getDescription() // fail point
        // do something with it...
    }
}

Сервис

class SystemBService{
    public SystemBObject getSomethingFromB(SomethingFromBRequest req){
        return new SystemBObjectFactory.getObject(req);
    }
}

Переносимый объект

Версия 1

class SystemBObject{
     String key;
     Integer year;
     Integer month;
     Integer day;

     ... // getters and setters etc;
}

Версия 2

class SystemBObject{
     String key;
     BDate date;
     ... // getters and setters etc;
}

class BDate{
     Integer year;
     Integer month;
     Integer day;
     ... // getters and setters etc;

}

Объект запроса

Версия 1

class SomethingFromBRequest {
     String key;
     ... // getters and setters etc;
}

Версия 2

class SomethingFromBRequest {
     String key;
     BDate afterDate;
     BDate beforeDate;
     ... // getters and setters etc;
}

Сценарии сбоев

Если клиент System A версии 1 вызывает службу System B версии 2, он может выйти из строя on:

  • отсутствующие методы на SystemBObject (getYear(), getMonth(), getDay())
  • Неизвестный тип BDate

Если клиент System A версии 2 вызывает службу System B версии 1, он может выйти из строя на:

  • Неизвестный тип BDate в SomethingFromBRequest (клиент использует новый объект запроса B, который B-версия 1 не распознает)
  • Если клиент System A достаточно умен, чтобы использовать версию 1 объекта запроса, он может не работать с отсутствующими методами в объекте SystemBObject (getDate())

Если клиент System B версии 1 вызывает службу System A версии 2, он может выйти из строя on:

  • Введите missmatch или overflow на SystemAObject (возвращается Long, но ожидается Integer)

Если клиент System B версии 2 вызывает службу System A версии 1, она может выйти из строя на:

  • Введите missmatch или overflow на SystemARequest (запрос Long вместо Integer)
  • Если запрос каким-то образом прошел, проблемы с литьем (заглушка Long, но служба возвращает Integer, которая несовместима во всех реализациях WS)

Возможные решения

  • Используйте числа при продвижении версий: например. SystemAObject1, SystemBRequest2 и т.д., но при этом отсутствует API для соответствия исходной/целевой версии
  • В сигнатуре передать XML, а не объекты (yuck, pass escaped XML в XML, двойная сериализация, десериализация/синтаксический анализ, unparsing)
  • Другое: например. У документа/литерала/WS-I есть средство правовой защиты?
4b9b3361

Ответ 1

Я предпочитаю метод управления версиями Salesforce.com. Каждая версия веб-служб получает отдельный URL-адрес в формате:

http://api.salesforce.com/{version}/{serviceName}

Итак, у вас будут URL-адреса веб-сервисов, которые выглядят следующим образом:

http://api.salesforce.com/14/Lead

http://api.salesforce.com/15/Lead

и т.д.

С помощью этого метода вы получаете преимущества:

  • Вы всегда знаете, с какой версией вы разговариваете.

  • Поддерживается обратная совместимость.

  • Вам не нужно беспокоиться о проблемах с зависимостями. Каждая версия имеет полный набор услуг. Вам просто нужно убедиться, что вы не смешиваете версии между вызовами (но это зависит от потребителя услуги, а не от разработчика).

Ответ 2

Решение состоит в том, чтобы избежать несовместимых изменений в ваших типах.

Возьмем, к примеру, SystemBObject. Вы описываете "версию 1" и "версию 2" этого типа, но они не одинаковы. Совместимое изменение этого типа включает только добавление свойств, а не изменение типа любых существующих свойств. Ваше гипотетическое "обновление версии" нарушило оба этих ограничения.

Следуя этой гильдии, вы можете избежать всех описанных вами проблем.

Поэтому, если это ваше определение типа в версии 1

class SystemBObject{  // version 1
    String key;  
    Integer year;  
    Integer month;  
    Integer day;  

    ... // getters and setters etc;  
}  

Тогда это не может быть вашим определением типа в v2:

// version 2 - NO NO NO 
class SystemBObject{ 
    String key; 
    BDate date; 
    ... // getters and setters etc; 
} 

... потому что он устранил существующие поля. Если это изменение, которое вам нужно сделать, это не новая "версия", это новый тип и должен быть назван как таковой, как в коде, так и в формате сериализации.

Другой пример: если это ваш существующий тип v1:

class SomethingFromARequest {   
    Integer requestedId;   
    ... // getters and setters etc;      
}   

... тогда это не является допустимым "v2" этого типа:

class SomethingFromARequest {   
    Long requestedId;   
    ... // getters and setters etc;      
}   

... потому что вы изменили тип существующего свойства.

Эти ограничения более подробно объясняются главным образом технологически нейтральным способом в статье Microsoft Service Versioning.


Помимо исключения этого источника несовместимости, вы можете и должны включать номер версии в тип. Это может быть простой серийный номер. Если у вас есть привычка регистрировать или проверять сообщения, а пропускная способность и пространство для хранения данных не являются проблемой, вы можете захотеть увеличить простое целое число с помощью UUID для идентификации экземпляра каждой уникальной версии типа.

Кроме того, вы можете проектировать форвардную совместимость в объекты передачи данных, используя слабую обработку и отображение "дополнительных" данных в "дополнительное" поле. Если XML - это ваш формат сериализации, вы можете использовать xsd: xmlAny или xsd: any и processContents = "lax" для захвата любых непризнанных элементов схемы, когда служба v1 получает запрос v2 (больше). Если ваш формат сериализации - JSON, с его более открытой моделью контента, то это бесплатно.

Ответ 3

Я знаю, что это уже поздно, но я довольно глубоко вникаю в эту проблему. Я действительно думаю, что лучший ответ включает в себя еще один кусочек головоломки: посредник службы. Microsoft Managed Services Engine - пример одного - я уверен, что другие существуют. В основном, изменив пространство имен XML вашего веб-сервиса (чтобы указать номер версии или дату, как упоминается в связанной статье), вы разрешаете посреднику возможность маршрутизировать различные клиентские вызовы на соответствующие серверные реализации. Дополнительная (и, IMHO, очень крутая) функция MSE - это возможность выполнять преобразования на основе политик. Вы можете определить преобразования XSLT, которые конвертируют запросы v1 в запросы v2, и ответы v2 в ответы v1, что позволяет вам удалять реализации служб v1 без нарушения реализации клиента.

Ответ 4

Я думаю, что что-то еще, что нужно иметь в виду, это ваша клиентская база, публично публикую эту услугу или она ограничена набором известных агентов?

Я участвую в последней ситуации, и мы обнаружили, что это не так сложно решить с помощью простой коммуникации/привлечения внимания.

Хотя это косвенно связано с вашим вопросом, мы обнаружили, что, основывая наш номер версии на совместимость, кажется, работает достаточно хорошо. Использование A.B.C в качестве примера...

  • A: Изменения, требующие перекомпиляции (прерывает обратную совместимость)
  • B: Изменения, которые не требуют перекомпиляции, но без дополнительных функций недоступны (новые операции и т.д.).
  • C: Изменения в основной механике, которые не изменяют WSDL