Каковы ваши лучшие практики управления версиями WebService? - PullRequest
19 голосов
/ 20 января 2010

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

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

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

Система A

Клиент

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

Клиент

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;
}

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

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

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

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

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

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

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

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

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

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

  1. Используйте числа при продвижении версий: например, SystemAObject1, SystemBRequest2 и т. Д., Но отсутствует API для соответствия исходной / целевой версии
  2. В сигнатуре передайте XML, а не объекты (чёрт, передайте экранированный XML в XML, двойная сериализация, десериализация / разбор, разбор)
  3. Другое: например, есть ли в Document / literal / WS-I средство правовой защиты?

Ответы [ 4 ]

23 голосов
/ 20 января 2010

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

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

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

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

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

и так далее ...

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

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

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

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

4 голосов
/ 20 января 2010

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

Взять, к примеру, 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 по управлению версиями .


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

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

3 голосов
/ 29 апреля 2010

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...