@TorwaldSergesson
Люблю Python и море (хотя вижу его редко)

Каким образом лучше организовать API-библиотеку?

Вопрос в следующем. Есть некоторое серверное программное обеспечение. Есть возможность управлять им как через веб-интерфейс, так и при помощи команд через Telnet. Сейчас требуется создать обертку для этих команд на Python. Есть официальные библиотеки, которые работают, так же через Telnet, но они на других языках. Вернее, я ее уже создал, но хотелось бы убедиться, в правильном ли направлении я пошел. В связи с этим вопросы.
1. Нормально ли будет для этих целей использовать telnetlib или все же стоило применить что-нибудь другое, типа socket?
2. Нормальна ли такая организация организация кода? Один метод-исполнитель запроса и один метод-парсер, а остальные просто используют метод _exec.
#apiexecutor.py

class APIExecutor:
    def _exec(self, query):
        ...
        return self._parse(result)

    def do_something1(self, arg1, arg2):
        query = "DOSOMETHING %s FOR %s" % (arg1, arg2)
        return self._exec(query)

   def do_some_else(self, arg1):
       query = "DOSOMEELSE %s" % arg1
       return self._exec(query)

3. В официальных библиотеках к этому ПО все функции (около 150) лежат в одном файле. Правильным ли будет их тут так же объединить в один файл, либо разделить их в разные файлы и сделать манипуляции в __init__.py?
4. В официальных библиотеках функции возвращают данные в примитивных типах (массивы, строки, словари). Как Вам кажется, стоит ли оставить такое поведение в моей обертке, либо сделать нормальные классы, вроде Аккаунт, Сервер, Кластер, Правило и т.д. для объектов ПО. И если делать нормальными классами, то как тогда реализовать человеческую работу с ними? В моей голове есть такой вариант создать дополнительную обертку над моей библиотекой, которая будет получать примитивные данные и превращать их в классы. Нормальная ли будет подобная архитектура, или что-то не так.
class BaseClass:
    def __init__(self, connection):
        self._connection = connection

class Account(BaseClass):
    def __init__(self, connection, account_name, **kwargs):
        self.account_name = account_name
        for attr, value in kwargs:
              setattr(self, attr, value)
        super(Account, self).__init__(connection)

   def create(self):
       r = self._connection.create_account(self.account_name)
       if not r['success']:
            raise Error

   def rename(self, new_name):
       r = self._connection.rename_account(self.account_name, new_name)
       if not r['success']:
           raise Error
      self.account_name = r['account_name']


Буду крайне благодарен за мнения, советы и какую-либо информация по теме. Спасибо!
  • Вопрос задан
  • 2522 просмотра
Решения вопроса 2
qmax
@qmax
программер
Ну вообще всё завист от целей создания API и способов его использования.
1. Если целевой сервис доступен по telnet, то вполне логично использовать telnetlib.
У http куча накладных расходов и куча лишнего в запросах и ответах,
кроме того, он всётаки больше подходит для REST-приложеинй (управление ресурсами), а у вас, судя по всему RPC-style (вызов функций).

2. Если в куче методов необходимо выполнять одни и теже манипуляции, то вполне очевидно объединить эти манипуляции в общий метод.
Но если ваша обёртка не обладает состоянием и не инкапсулирует никакие данные (например, параметры авторизации или доступа к сервису) - то это модуль, а не класс.
И уж темболее не стоит использовать классы из питона 2.0

3. зависит от того, образует ли множество методов имеющие смысл независимые подмножества. (например метод, использующие только Аккаунт)

4. необходимость в классах Аккаунт, Сервер, Кластер, Правило зависит от того, являются ли они классами в смысле ООП: инкапсулируют ли какието данные (или просто содержат примитивы), содержат ли какие-то методы манипуляции с ними.
Вариантов глобально два:
1. возвращать инстансы этих классов и принимать их параметрами из методов вашей обёртки api
т.е. сделать классы просто типизированными контейнерами данных
2. перенести вызовы api в методы этих классов, ну и засунуть в них ссылку на порождающий их экземпляр api.
Зависит от того, существуют ли вообще такие методы api, которые однозначно идентифицируются как методы какого-либо класса.
Ответ написан
Tiendil
@Tiendil
Разработчик ПО.
KISS

1. Если библиотека работает с телнетом, логично использовать специализированную либу.
2. Если метод инкапсулирует все низкоуровневые операции по обработке соединения и передачи данных, то ОК.
3. Если Вы портируете библиотеку, то правильным будет сохранить аналогичные интерфейсы. Как конкретно они будут реализованы — не важно. Для пользователей библиотеки её реализация — это чёрный ящик. Поэтому разбивайте по файлам как удобно в данной конкретной реализации. При необходимости пробросите нужные импорты куда надо (например, в __init__.py).
4. см. пункт 3. Делайте как в аналогах, если понадобится, потом добавите обёртку с высокоуровневым интерфейсом.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы