From 0049a93c27f3eb13ad7e8cc4c302dad94bbae0f5 Mon Sep 17 00:00:00 2001
From: Vincent Texier <vit@free.fr>
Date: Tue, 10 Jul 2018 11:55:07 +0200
Subject: [PATCH] issue #56 WIP - Implement Client.post() method everywhere
 needed

---
 duniterpy/api/bma/blockchain.py         | 163 +++++++++++------------
 duniterpy/api/bma/network.py            | 166 ++++++++++++------------
 duniterpy/api/bma/tx.py                 |  27 ++--
 duniterpy/api/bma/wot.py                |  70 +++++-----
 examples/create_and_publish_identity.py |  45 +++----
 examples/save_revoke_document.py        |  72 +++++-----
 examples/send_certification.py          |  58 +++++----
 examples/send_transaction.py            |  48 ++++---
 8 files changed, 323 insertions(+), 326 deletions(-)

diff --git a/duniterpy/api/bma/blockchain.py b/duniterpy/api/bma/blockchain.py
index c79b8ecc..4026d392 100644
--- a/duniterpy/api/bma/blockchain.py
+++ b/duniterpy/api/bma/blockchain.py
@@ -16,6 +16,10 @@
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # vit
 import logging
+from typing import Union
+
+from aiohttp import ClientSession
+
 from duniterpy.api.client import Client, RESPONSE_AIOHTTP
 
 logger = logging.getLogger("duniter/blockchain")
@@ -174,76 +178,75 @@ BLOCK_NUMBERS_SCHEMA = {
 }
 
 PARAMETERS_SCHEMA = {
-        "type": "object",
-        "properties":
+    "type": "object",
+    "properties":
         {
-              "currency": {
-                  "type": "string"
-              },
-              "c": {
-                  "type": "number"
-              },
-              "dt": {
-                  "type": "number"
-              },
-              "ud0": {
-                  "type": "number"
-              },
-              "sigPeriod": {
-                  "type": "number"
-              },
-              "sigStock": {
-                  "type": "number"
-              },
-              "sigWindow": {
-                  "type": "number"
-              },
-              "sigValidity": {
-                  "type": "number"
-              },
-              "sigQty": {
-                  "type": "number"
-              },
-              "xpercent": {
-                  "type": "number"
-              },
-              "msValidity": {
-                  "type": "number"
-              },
-              "stepMax": {
-                  "type": "number"
-              },
-              "medianTimeBlocks": {
-                  "type": "number"
-              },
-              "avgGenTime": {
-                  "type": "number"
-              },
-              "dtDiffEval": {
-                  "type": "number"
-              },
-              "percentRot": {
-                  "type": "number"
-              },
-              "udTime0": {
-                  "type": "number"
-              },
-              "udReevalTime0": {
-                  "type": "number"
-              },
-              "dtReeval": {
-                  "type": "number"
-              }
+            "currency": {
+                "type": "string"
             },
-        "required": ["currency", "c", "dt", "ud0", "sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock",
-                     "sigWindow", "msValidity", "stepMax", "medianTimeBlocks",
-                     "avgGenTime", "dtDiffEval", "percentRot", "udTime0", "udReevalTime0", "dtReeval"]
-    }
-
+            "c": {
+                "type": "number"
+            },
+            "dt": {
+                "type": "number"
+            },
+            "ud0": {
+                "type": "number"
+            },
+            "sigPeriod": {
+                "type": "number"
+            },
+            "sigStock": {
+                "type": "number"
+            },
+            "sigWindow": {
+                "type": "number"
+            },
+            "sigValidity": {
+                "type": "number"
+            },
+            "sigQty": {
+                "type": "number"
+            },
+            "xpercent": {
+                "type": "number"
+            },
+            "msValidity": {
+                "type": "number"
+            },
+            "stepMax": {
+                "type": "number"
+            },
+            "medianTimeBlocks": {
+                "type": "number"
+            },
+            "avgGenTime": {
+                "type": "number"
+            },
+            "dtDiffEval": {
+                "type": "number"
+            },
+            "percentRot": {
+                "type": "number"
+            },
+            "udTime0": {
+                "type": "number"
+            },
+            "udReevalTime0": {
+                "type": "number"
+            },
+            "dtReeval": {
+                "type": "number"
+            }
+        },
+    "required": ["currency", "c", "dt", "ud0", "sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock",
+                 "sigWindow", "msValidity", "stepMax", "medianTimeBlocks",
+                 "avgGenTime", "dtDiffEval", "percentRot", "udTime0", "udReevalTime0", "dtReeval"]
+}
 
 MEMBERSHIPS_SCHEMA = {
-        "type": "object",
-        "properties":
+    "type": "object",
+    "properties":
         {
             "pubkey": {
                 "type": "string"
@@ -279,9 +282,8 @@ MEMBERSHIPS_SCHEMA = {
                 }
             }
         },
-        "required": ["pubkey", "uid", "sigDate", "memberships"]
-    }
-
+    "required": ["pubkey", "uid", "sigDate", "memberships"]
+}
 
 BLOCKS_SCHEMA = {
     "type": "array",
@@ -323,15 +325,15 @@ async def memberships(client: Client, search: str) -> dict:
     return await client.get(MODULE + '/memberships/%s' % search, schema=MEMBERSHIPS_SCHEMA)
 
 
-async def membership(client: Client, _membership: str):
+async def membership(client: Client, membership_signed_raw: str):
     """
     POST a Membership document
 
     :param client: Client to connect to the api
-    :param _membership: Membership signed raw document
+    :param membership_signed_raw: Membership signed raw document
     :rtype: aiohttp.ClientResponse
     """
-    return await client.post(MODULE + '/membership', {'membership': _membership}, rtype=RESPONSE_AIOHTTP)
+    return await client.post(MODULE + '/membership', {'membership': membership_signed_raw}, rtype=RESPONSE_AIOHTTP)
 
 
 async def current(client: Client) -> dict:
@@ -344,22 +346,21 @@ async def current(client: Client) -> dict:
     return await client.get(MODULE + '/current', schema=BLOCK_SCHEMA)
 
 
-async def block(client: Client, number: int = 0, _block: dict = None, signature: str = None):
+async def block(client: Client, number: int = 0, block_raw: str = None, signature: str = None) -> Union[dict,
+                                                                                                        ClientSession]:
     """
     GET/POST a block from/to the blockchain
 
     :param client: Client to connect to the api
     :param number: Block number to get
-    :param dict _block: Block document to post
-    :param str signature: Signature of the block document issuer
+    :param block_raw: Block document to post
+    :param signature: Signature of the block document issuer
     :rtype: dict
     """
-
-    # client = API(connection, MODULE)
-    # # POST block
-    # if _block is not None and signature is not None:
-    #     return await client.requests_post('/block', block=_block, signature=signature)
-
+    # POST block
+    if block_raw is not None and signature is not None:
+        return await client.post(MODULE + '/block', {'block': block_raw, 'signature': signature},
+                                 rtype=RESPONSE_AIOHTTP)
     # GET block
     return await client.get(MODULE + '/block/%d' % number, schema=BLOCK_SCHEMA)
 
diff --git a/duniterpy/api/bma/network.py b/duniterpy/api/bma/network.py
index eedaaecc..cebb5ba0 100644
--- a/duniterpy/api/bma/network.py
+++ b/duniterpy/api/bma/network.py
@@ -16,90 +16,92 @@
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # vit
 import logging
-from duniterpy.api.client import Client
-from duniterpy.documents.peer import Peer
+
+from aiohttp import ClientSession
+
+from duniterpy.api.client import Client, RESPONSE_AIOHTTP
 
 logger = logging.getLogger("duniter/network")
 
 MODULE = 'network'
 
 PEERING_SCHEMA = {
-        "type": "object",
-        "properties": {
-          "version": {
-              "type": ["number", "string"]
-          },
-          "currency": {
-              "type": "string"
-          },
-          "pubkey": {
-              "type": "string"
-          },
-          "endpoints": {
-              "type": "array",
-              "items": {
-                  "type": "string"
-              }
-          },
-          "signature": {
-              "type": "string"
-          }
+    "type": "object",
+    "properties": {
+        "version": {
+            "type": ["number", "string"]
+        },
+        "currency": {
+            "type": "string"
         },
-        "required": ["version", "currency", "pubkey", "endpoints", "signature"]
-    }
+        "pubkey": {
+            "type": "string"
+        },
+        "endpoints": {
+            "type": "array",
+            "items": {
+                "type": "string"
+            }
+        },
+        "signature": {
+            "type": "string"
+        }
+    },
+    "required": ["version", "currency", "pubkey", "endpoints", "signature"]
+}
 
 PEERS_SCHEMA = schema = {
-        "type": ["object"],
-        "properties": {
-            "depth": {
-                "type": "number"
-            },
-            "nodesCount": {
-                "type": "number"
-            },
-            "leavesCount": {
-                "type": "number"
-            },
-            "root": {
-                "type": "string"
-            },
-            "hash": {
-                "type": "string"
-            },
-            "value": {
-                "type": "object",
-                "properties": {
-                    "version": {
-                        "type": "string"
-                    },
-                    "currency": {
-                        "type": "string"
-                    },
-                    "pubkey": {
-                        "type": "string"
-                    },
-                    "endpoints": {
-                        "type": "array",
-                        "items": {
-                            "type": "string"
-                        }
-                    },
-                    "signature": {
+    "type": ["object"],
+    "properties": {
+        "depth": {
+            "type": "number"
+        },
+        "nodesCount": {
+            "type": "number"
+        },
+        "leavesCount": {
+            "type": "number"
+        },
+        "root": {
+            "type": "string"
+        },
+        "hash": {
+            "type": "string"
+        },
+        "value": {
+            "type": "object",
+            "properties": {
+                "version": {
+                    "type": "string"
+                },
+                "currency": {
+                    "type": "string"
+                },
+                "pubkey": {
+                    "type": "string"
+                },
+                "endpoints": {
+                    "type": "array",
+                    "items": {
                         "type": "string"
                     }
                 },
-                "required": ["version", "currency", "pubkey", "endpoints", "signature"]
-            }
-        },
-        "oneOf": [
-            {
-                "required": ["depth", "nodesCount", "leavesCount", "root"]
+                "signature": {
+                    "type": "string"
+                }
             },
-            {
-                "required": ["hash", "value"]
-            }
-        ]
-    }
+            "required": ["version", "currency", "pubkey", "endpoints", "signature"]
+        }
+    },
+    "oneOf": [
+        {
+            "required": ["depth", "nodesCount", "leavesCount", "root"]
+        },
+        {
+            "required": ["hash", "value"]
+        }
+    ]
+}
 
 
 async def peering(client: Client) -> dict:
@@ -127,16 +129,12 @@ async def peers(client: Client, leaves: bool = False, leaf: str = ""):
         return await client.get(MODULE + '/peering/peers', {"leaf": leaf}, schema=PEERS_SCHEMA)
 
 
-# async def peer(client: Client, entry: Peer = None, signature: str = None) -> dict:
-#     """
-#     POST a Peer document with his signature
-#
-#     :param client: Client to connect to the api
-#     :param entry: Peer document
-#     :param signature: Signature of the document issuer
-#     :rtype: dict
-#     """
-#
-#     client = API(connection, MODULE)
-#     r = await client.requests_post('/peering/peers', entry=entry, signature=signature)
-#     return r
+async def peer(client: Client, peer_signed_raw: str) -> ClientSession:
+    """
+    POST a Peer signed raw document
+
+    :param client: Client to connect to the api
+    :param peer_signed_raw: Peer signed raw document
+    :rtype: ClientSession
+    """
+    return await client.post(MODULE + '/peering/peers', {'peer': peer_signed_raw}, rtype=RESPONSE_AIOHTTP)
diff --git a/duniterpy/api/bma/tx.py b/duniterpy/api/bma/tx.py
index dfeae417..a716fe15 100644
--- a/duniterpy/api/bma/tx.py
+++ b/duniterpy/api/bma/tx.py
@@ -16,8 +16,10 @@
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # vit
 import logging
-from duniterpy.api.client import Client
-from duniterpy.documents import Transaction
+
+from aiohttp import ClientSession
+
+from duniterpy.api.client import Client, RESPONSE_AIOHTTP
 
 logger = logging.getLogger("duniter/tx")
 
@@ -209,18 +211,15 @@ async def history(client: Client, pubkey: str) -> dict:
     return await client.get(MODULE + '/history/%s' % pubkey, schema=HISTORY_SCHEMA)
 
 
-# async def process(client: Client, transaction: Transaction):
-#     """
-#     POST a transaction
-#
-#     :param client: Client to connect to the api
-#     :param transaction: Transaction document
-#     :rtype: aiohttp.ClientResponse
-#     """
-#     client = API(connection, MODULE)
-#
-#     r = await client.requests_post('/process', transaction=transaction)
-#     return r
+async def process(client: Client, transaction_signed_raw: str) -> ClientSession:
+    """
+    POST a transaction raw document
+
+    :param client: Client to connect to the api
+    :param transaction_signed_raw: Transaction signed raw document
+    :rtype: ClientResponse
+    """
+    return await client.post(MODULE + '/process', {'transaction': transaction_signed_raw}, rtype=RESPONSE_AIOHTTP)
 
 
 async def sources(client: Client, pubkey: str):
diff --git a/duniterpy/api/bma/wot.py b/duniterpy/api/bma/wot.py
index 4b655d54..01e4cb4b 100644
--- a/duniterpy/api/bma/wot.py
+++ b/duniterpy/api/bma/wot.py
@@ -16,7 +16,10 @@
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # vit
 import logging
-from duniterpy.api.client import Client
+
+from aiohttp import ClientSession
+
+from duniterpy.api.client import Client, RESPONSE_AIOHTTP
 
 logger = logging.getLogger("duniter/wot")
 
@@ -97,7 +100,6 @@ CERTIFICATIONS_SCHEMA = {
     "required": ["pubkey", "uid", "isMember", "certifications"]
 }
 
-
 MEMBERS_SCHEMA = {
     "type": "object",
     "properties": {
@@ -117,7 +119,6 @@ MEMBERS_SCHEMA = {
     "required": ["results"]
 }
 
-
 REQUIREMENTS_SCHEMA = {
     "type": "object",
     "properties": {
@@ -298,46 +299,37 @@ LOOKUP_SCHEMA = {
 }
 
 
-# async def add(client: Client, identity: str) -> dict:
-#     """
-#     POST identity document
-#
-#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-#     :param duniterpy.documents.certification.Identity identity: Identity document
-#     :rtype: aiohttp.ClientResponse
-#     """
-#     client = API(connection, URL_PATH)
-#
-#     r = await client.requests_post('/add', identity=identity)
-#     return r
+async def add(client: Client, identity_signed_raw: str) -> ClientSession:
+    """
+    POST identity raw document
 
+    :param client: Client to connect to the api
+    :param identity_signed_raw: Identity raw document
+    :rtype: aiohttp.ClientResponse
+    """
+    return await client.post(MODULE + '/add', {'identity': identity_signed_raw}, rtype=RESPONSE_AIOHTTP)
 
-# async def certify(connection, cert):
-#     """
-#     POST certification document
-#
-#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-#     :param duniterpy.documents.certification.Certification cert: Certification document
-#     :rtype: aiohttp.ClientResponse
-#     """
-#     client = API(connection, URL_PATH)
-#
-#     r = await client.requests_post('/certify', cert=cert)
-#     return r
 
+async def certify(client: Client, certification_signed_raw: str) -> ClientSession:
+    """
+    POST certification raw document
 
-# async def revoke(connection, revocation):
-#     """
-#     POST revocation document
-#
-#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-#     :param duniterpy.documents.certification.Revocation revocation: Certification document
-#     :rtype: aiohttp.ClientResponse
-#     """
-#     client = API(connection, URL_PATH)
-#
-#     r = await client.requests_post('/revoke', revocation=revocation)
-#     return r
+    :param client: Client to connect to the api
+    :param certification_signed_raw: Certification raw document
+    :rtype: aiohttp.ClientResponse
+    """
+    return await client.post(MODULE + '/certify', {'cert': certification_signed_raw}, rtype=RESPONSE_AIOHTTP)
+
+
+async def revoke(client: Client, revocation_signed_raw: str) -> ClientSession:
+    """
+    POST revocation document
+
+    :param client: Client to connect to the api
+    :param revocation_signed_raw: Certification raw document
+    :rtype: aiohttp.ClientResponse
+    """
+    return await client.post(MODULE + '/revoke', {'revocation': revocation_signed_raw}, rtype=RESPONSE_AIOHTTP)
 
 
 async def lookup(client: Client, search: str) -> dict:
diff --git a/examples/create_and_publish_identity.py b/examples/create_and_publish_identity.py
index 60ba1d92..f73a8dfd 100644
--- a/examples/create_and_publish_identity.py
+++ b/examples/create_and_publish_identity.py
@@ -1,13 +1,11 @@
 import asyncio
-import aiohttp
 import getpass
 
 import duniterpy.api.bma as bma
-from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.api.client import Client
 from duniterpy.documents import BlockUID, Identity
 from duniterpy.key import SigningKey
 
-
 # CONFIG #######################################
 
 # You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT]
@@ -15,23 +13,18 @@ from duniterpy.key import SigningKey
 # Here we use the secure BASIC_MERKLED_API (BMAS)
 BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
-# Your unique identifier in the Web of Trust
-UID = "MyIdentityTest"
 
 ################################################
-# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request
-# ( http://pythonhosted.org/aiohttp )
-AIOHTTP_SESSION = aiohttp.ClientSession()
 
 
-def get_identity_document(current_block, uid, salt, password):
+def get_identity_document(current_block: dict, uid: str, salt: str, password: str) -> Identity:
     """
     Get an Identity document
 
-    :param dict current_block: Current block data
-    :param str uid: Unique Identifier
-    :param str salt: Passphrase of the account
-    :param str password: Password of the account
+    :param current_block: Current block data
+    :param uid: Unique IDentifier
+    :param salt: Passphrase of the account
+    :param password: Password of the account
 
     :rtype: Identity
     """
@@ -62,11 +55,18 @@ async def main():
     """
     Main code
     """
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos to test the connection
+    response = await client(bma.node.summary)
+    print(response)
 
-    # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
     # capture current block to get version and currency and blockstamp
-    current_block = await bma.blockchain.current(connection)
+    current_block = await client(bma.blockchain.current)
+
+    # prompt entry
+    uid = input("Enter your Unique IDentifier (pseudonym): ")
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
@@ -75,18 +75,19 @@ async def main():
     password = getpass.getpass("Enter your password: ")
 
     # create our signed identity document
-    identity = get_identity_document(current_block, UID, salt, password)
+    identity = get_identity_document(current_block, uid, salt, password)
 
     # send the identity document to the node
-    response = await bma.wot.add(connection, identity.signed_raw())
+    response = await client(bma.wot.add, identity.signed_raw())
     if response.status == 200:
         print(await response.text())
     else:
         print("Error while publishing identity : {0}".format(await response.text()))
-    response.close()
+
+    # Close client aiohttp session
+    await client.close()
+
 
 # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
 # ( https://docs.python.org/3/library/asyncio.html )
-
-with AIOHTTP_SESSION:
-    asyncio.get_event_loop().run_until_complete(main())
+asyncio.get_event_loop().run_until_complete(main())
diff --git a/examples/save_revoke_document.py b/examples/save_revoke_document.py
index ae08e412..e5fd24e1 100644
--- a/examples/save_revoke_document.py
+++ b/examples/save_revoke_document.py
@@ -1,11 +1,11 @@
 import asyncio
-import aiohttp
+import getpass
+import os
+
 import duniterpy.api.bma as bma
-from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.api.client import Client
 from duniterpy.documents import Revocation, BlockUID, Identity
 from duniterpy.key import SigningKey
-import getpass
-import os
 
 if "XDG_CONFIG_HOME" in os.environ:
     home_path = os.environ["XDG_CONFIG_HOME"]
@@ -26,27 +26,27 @@ BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 # WARNING : Hide this file in a safe and secure place
 # If one day you forget your credentials,
 # you'll have to use your private key instead
-REVOKE_DOCUMENT_FILE_PATH = os.path.join(home_path, "duniter_account_revoke_document.txt")
-
-################################################
-AIOHTTP_SESSION = aiohttp.ClientSession()
+REVOCATION_DOCUMENT_FILE_PATH = os.path.join(home_path, "duniter_account_revocation_document.txt")
 
 # Current protocol version
 PROTOCOL_VERSION = 10
 
 
-async def get_identity_document(connection, currency, pubkey):
+################################################
+
+
+async def get_identity_document(client: Client, currency: str, pubkey: str) -> Identity:
     """
     Get the Identity document of the pubkey
 
-    :param bma.connection.ConnectionHandler connection: Connection handler
-    :param str currency: Currency name
-    :param str pubkey: Public key
+    :param client: Client to connect to the api
+    :param currency: Currency name
+    :param pubkey: Public key
 
     :rtype: Identity
     """
     # Here we request for the path wot/lookup/pubkey
-    lookup_data = await bma.wot.lookup(connection, pubkey)
+    lookup_data = await client(bma.wot.lookup, pubkey)
 
     # init vars
     uid = None
@@ -74,28 +74,34 @@ async def get_identity_document(connection, currency, pubkey):
             )
 
 
-def get_revoke_document(identity, salt, password):
+def get_signed_raw_revocation_document(identity: Identity, salt: str, password: str) -> str:
     """
     Generate account revocation document for given identity
 
-    :param Identity identity: Self Certification of the identity
-    :param str salt: Salt
-    :param str password: Password
+    :param identity: Self Certification of the identity
+    :param salt: Salt
+    :param password: Password
 
-    :return: the raw signed revokation document
     :rtype: str
     """
-    document = Revocation(PROTOCOL_VERSION, identity.currency, identity.pubkey, "")
+    revocation = Revocation(PROTOCOL_VERSION, identity.currency, identity.pubkey, "")
 
     key = SigningKey(salt, password)
-    document.sign(identity, [key])
-    return document.signed_raw(identity)
+    revocation.sign(identity, [key])
+    return revocation.signed_raw(identity)
 
 
 async def main():
     """
     Main code
     """
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos to test the connection
+    response = await client(bma.node.summary)
+    print(response)
+
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
 
@@ -113,27 +119,27 @@ async def main():
         print("Bad credentials!")
         exit(0)
 
-    # connection handler from BMAS endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
     # capture current block to get currency name
-    current_block = await bma.blockchain.current(connection)
+    current_block = await client(bma.blockchain.current)
 
     # create our Identity document to sign the revoke document
-    identity_document = await get_identity_document(connection, current_block['currency'], pubkey)
+    identity_document = await get_identity_document(client, current_block['currency'], pubkey)
 
     # get the revoke document
-    revoke_document = get_revoke_document(identity_document, salt, password)
+    revocation_signed_raw_document = get_signed_raw_revocation_document(identity_document, salt, password)
 
     # save revoke document in a file
-    fp = open(REVOKE_DOCUMENT_FILE_PATH, 'w')
-    fp.write(revoke_document)
+    fp = open(REVOCATION_DOCUMENT_FILE_PATH, 'w')
+    fp.write(revocation_signed_raw_document)
     fp.close()
 
     # document saved
-    print("Revoke document saved in %s" % REVOKE_DOCUMENT_FILE_PATH)
+    print("Revocation document saved in %s" % REVOCATION_DOCUMENT_FILE_PATH)
+
+    # Close client aiohttp session
+    await client.close()
 
 
-with AIOHTTP_SESSION:
-    # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
-    # ( https://docs.python.org/3/library/asyncio.html )
-    asyncio.get_event_loop().run_until_complete(main())
+# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
+# ( https://docs.python.org/3/library/asyncio.html )
+asyncio.get_event_loop().run_until_complete(main())
diff --git a/examples/send_certification.py b/examples/send_certification.py
index 1391a189..0da9a8ee 100644
--- a/examples/send_certification.py
+++ b/examples/send_certification.py
@@ -1,12 +1,11 @@
 import asyncio
-import aiohttp
 import getpass
+
 import duniterpy.api.bma as bma
-from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.api.client import Client
 from duniterpy.documents import BlockUID, Identity, Certification
 from duniterpy.key import SigningKey
 
-
 # CONFIG #######################################
 
 # You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT]
@@ -14,25 +13,22 @@ from duniterpy.key import SigningKey
 # Here we use the secure BASIC_MERKLED_API (BMAS)
 BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
-################################################
 
-# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request
-# ( http://pythonhosted.org/aiohttp )
-AIOHTTP_SESSION = aiohttp.ClientSession()
+################################################
 
 
-async def get_identity_document(connection, current_block, pubkey):
+async def get_identity_document(client: Client, current_block: dict, pubkey: str) -> Identity:
     """
     Get the identity document of the pubkey
 
-    :param bma.connection.ConnectionHandler connection: Connection handler
-    :param dict current_block: Current block data
-    :param str pubkey: UID/Public key
+    :param client: Client to connect to the api
+    :param current_block: Current block data
+    :param pubkey: UID/Public key
 
     :rtype: Identity
     """
     # Here we request for the path wot/lookup/pubkey
-    lookup_data = await bma.wot.lookup(connection, pubkey)
+    lookup_data = await client(bma.wot.lookup, pubkey)
 
     # init vars
     uid = None
@@ -60,15 +56,16 @@ async def get_identity_document(connection, current_block, pubkey):
             )
 
 
-def get_certification_document(current_block, self_cert_document, from_pubkey, salt, password):
+def get_certification_document(current_block: dict, self_cert_document: Identity, from_pubkey: str, salt: str,
+                               password: str) -> Certification:
     """
     Create and return a Certification document
 
-    :param dict current_block: Current block data
-    :param Identity self_cert_document: Identity document
-    :param str from_pubkey: Pubkey of the certifier
-    :param str salt: Secret salt (DO NOT SHOW IT ANYWHERE, IT IS SECRET !!!)
-    :param str password: Secret password (DO NOT SHOW IT ANYWHERE, IT IS SECRET !!!)
+    :param current_block: Current block data
+    :param self_cert_document: Identity document
+    :param from_pubkey: Pubkey of the certifier
+    :param salt: Secret salt (DO NOT SHOW IT ANYWHERE, IT IS SECRET !!!)
+    :param password: Secret password (DO NOT SHOW IT ANYWHERE, IT IS SECRET !!!)
 
     :rtype: Certification
     """
@@ -92,8 +89,12 @@ async def main():
     """
     Main code
     """
-    # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos to test the connection
+    response = await client(bma.node.summary)
+    print(response)
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
@@ -108,25 +109,26 @@ async def main():
     pubkey_to = input("Enter certified pubkey: ")
 
     # capture current block to get version and currency and blockstamp
-    current_block = await bma.blockchain.current(connection)
+    current_block = await client(bma.blockchain.current)
 
     # create our Identity document to sign the Certification document
-    identity = await get_identity_document(connection, current_block, pubkey_to)
+    identity = await get_identity_document(client, current_block, pubkey_to)
 
     # send the Certification document to the node
     certification = get_certification_document(current_block, identity, pubkey_from, salt, password)
 
     # Here we request for the path wot/certify
-    response = await bma.wot.certify(connection, certification.signed_raw(identity))
+    response = await client(bma.wot.certify, certification.signed_raw(identity))
 
     if response.status == 200:
         print(await response.text())
     else:
         print("Error while publishing certification: {0}".format(await response.text()))
-    response.close()
 
-with AIOHTTP_SESSION:
+    # Close client aiohttp session
+    await client.close()
+
 
-    # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
-    # ( https://docs.python.org/3/library/asyncio.html )
-    asyncio.get_event_loop().run_until_complete(main())
+# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
+# ( https://docs.python.org/3/library/asyncio.html )
+asyncio.get_event_loop().run_until_complete(main())
diff --git a/examples/send_transaction.py b/examples/send_transaction.py
index 98b6d9fe..e169d782 100644
--- a/examples/send_transaction.py
+++ b/examples/send_transaction.py
@@ -1,9 +1,8 @@
 import asyncio
 import getpass
-import aiohttp
 
 from duniterpy.api import bma
-from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.api.client import Client
 from duniterpy.documents import BlockUID, Transaction
 from duniterpy.documents.transaction import InputSource, OutputSource, Unlock, SIGParameter
 from duniterpy.grammars.output import Condition, SIG
@@ -16,26 +15,21 @@ from duniterpy.key import SigningKey
 # Here we use the secure BASIC_MERKLED_API (BMAS)
 BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
-
-################################################
-
-
-# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request
-# ( http://pythonhosted.org/aiohttp )
-AIOHTTP_SESSION = aiohttp.ClientSession()
-
 # Version of the transaction document
 TRANSACTION_VERSION = 10
 
 
-def get_transaction_document(current_block, source, from_pubkey, to_pubkey):
+################################################
+
+
+def get_transaction_document(current_block: dict, source: dict, from_pubkey: str, to_pubkey: str) -> Transaction:
     """
     Return a Transaction document
 
-    :param dict current_block: Current block infos
-    :param dict source: Source to send
-    :param str from_pubkey: Public key of the issuer
-    :param str to_pubkey: Public key of the receiver
+    :param current_block: Current block infos
+    :param source: Source to send
+    :param from_pubkey: Public key of the issuer
+    :param to_pubkey: Public key of the receiver
 
     :return: Transaction
     """
@@ -95,8 +89,12 @@ async def main():
     """
     Main code
     """
-    # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos to test the connection
+    response = await client(bma.node.summary)
+    print(response)
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
@@ -111,10 +109,10 @@ async def main():
     pubkey_to = input("Enter recipient pubkey: ")
 
     # capture current block to get version and currency and blockstamp
-    current_block = await bma.blockchain.current(connection)
+    current_block = await client(bma.blockchain.current)
 
     # capture sources of account
-    response = await bma.tx.sources(connection, pubkey_from)
+    response = await client(bma.tx.sources, pubkey_from)
 
     if len(response['sources']) == 0:
         print("no sources found for account %s" % pubkey_to)
@@ -133,17 +131,17 @@ async def main():
     transaction.sign([key])
 
     # send the Transaction document to the node
-    response = await bma.tx.process(connection, transaction.signed_raw())
+    response = await client(bma.tx.process, transaction.signed_raw())
 
     if response.status == 200:
         print(await response.text())
     else:
         print("Error while publishing transaction: {0}".format(await response.text()))
-    response.close()
 
+    # Close client aiohttp session
+    await client.close()
 
-with AIOHTTP_SESSION:
 
-    # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
-    # ( https://docs.python.org/3/library/asyncio.html )
-    asyncio.get_event_loop().run_until_complete(main())
+# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
+# ( https://docs.python.org/3/library/asyncio.html )
+asyncio.get_event_loop().run_until_complete(main())
-- 
GitLab