This is our Tutorial page!
Watch our most recent
YouTube video
Have you ever wanted to build your own a Software Developer Kit (SDK)? Well you're in the right place.
In this tutorial, I will show you how to create a an SDK that will facilitate the usage of the Hedera mirror node API.
Hedera is the most used enterprise-grade public network for you to make your digital world exactly as it should be – yours. HBAR is the native, energy-efficient cryptocurrency of Hedera that powers the decentralized economy. Whether you're a start-up or enterprise, a creator or consumer, Hedera goes beyond blockchain for developers to create the next era of fast, fair, and secure applications.
Don't want to read this tutorial? Okay, fine. I have put this video together for you.
The code for the completed SDK can be found in this GitHub repository. Just clone down the project from the hedera_mirror_sdk repo, into your local development directory using the main branch:
Equally, as this is a reusable package, you can add it to your python project using pip.
pip install hedera-mirror-sdk
Okay, let's jump into it...
Syllabus:
This tutorial will focus on the following:
- Set up our environment
- Write some code
- Test the SDK
Set up our environment:
Let's get started!..
Open a your text editor of choice and cd into your development directory.
Lets begin by creating a working directory. We will be calling this SDK 'did_sdk'. Whilst in a terminal, use the following code to create a new directory.
mkdir did_sdk
cd did_sdk
Now create a fresh virtual environment.
paste the following code into your terminal.
python -m venv venv
Now fire up your virtual environment with one of the following commands.
#for windows
venv\Scripts\activate.bat
#for unix/mac
source venv/bin/activate
You can now install packages into the virtual environment. We will be using 2 packages in this SDK. Use the following code to install the necessary packages.
pip install requests
pip freeze > requirements.txt
Note: you will now have a requirements.txt in the project that details all project requirements.
Write some code:
This SDK is designed to facilitate the usage of the Hedera mirror node API which is a REST API. With this in mind, lets create a directory called 'rest'.
mkdir rest
cd rest
echo > __init__.py
This tutorial will focus on the 'account' endpoints listed on Hedera. However, the method we're using can scale across all endpoints. Lets create an account directory.
mkdir account
cd account
echo > __init__.py
Open account/__init__.py in your text editor and add the following code.
# coding=utf-8
class Account:
def __init__(self, did_sdk, base_url, domain, version ,**kwargs):
"""
Initialize the Account Domain
"""
super(Account, self)
self.did_sdk = did_sdk
self.base_url = base_url
self.domain = domain
self.version = version
def get(self, params=None, data=None, headers=None, auth=None, profile_id=None, domain_id=None, domain_action=None):
return self.did_sdk.request(
'get',
self.base_url,
self.domain,
self.version,
params=params,
data=data,
headers=headers,
auth=auth,
profile_id=profile_id,
domain_id=domain_id,
domain_action=domain_action
)
What have we done here? The idea of this code is to initiate and handle get requests made to the account endpoint. Most API's will have GET, POST, PUT and DELETE methods. when this is the case, you would simply add an extra method for each.
Now open rest/__init__.py and add the following code.
import os
import json
from urllib.parse import urlencode
import requests
def create_params(**kwargs):
'''
Used to create url parameters for API call
'''
url = kwargs.get("url")
params = kwargs.get("params")
if params:
query_string = urlencode(eval(params))
return f'{url}?{query_string}'
class PathBuilder:
'''
Used to build the correct API path that includes
parameters & filters
'''
def __init__(self, **kwargs):
self.base_url = kwargs.get('base_url')
self.domain = kwargs.get('domain')
self.version = kwargs.get('version')
self.profile_id = kwargs.get("profile_id")
self.domain_id = kwargs.get("domain_id")
self.domain_action = kwargs.get("domain_action")
self.params = kwargs.get('params')
def build(self):
paths = {
"domains":{
"account": {
"path": f'{self.version}/accounts',
"name": None
},
}
}
domain_info = paths['domains'][self.domain]
sections = [domain_info['path']]
if self.profile_id:
sections.append(self.profile_id)
if domain_info["name"]:
sections.append(domain_info["name"])
if self.domain_id:
sections.append(self.domain_id)
if self.domain_action:
sections.append(self.domain_action)
path = f'/{"/".join(sections)}'
url = f'{self.base_url}{path}'
#manage params and filtering
params = {}
operators = ["e", "lt", "lte", "gt", "gte"]
for param in self.params.keys():
if param in operators:
params['account.id'] = f'{param}:{self.params[param]}'
else:
params[param] = self.params[param]
if params:
url = create_params(params=json.dumps(params), url=url)
return [path, url]
class APIRequester:
'''
Used to make the request
'''
def __init__(self, **kwargs):
self.method = kwargs.get("method")
self.url = kwargs.get("url")
self.headers = kwargs.get("headers")
self.data = kwargs.get("data")
def get(self):
response = requests.get(
self.url,
headers=self.headers,
)
return response
class Client(object):
"""
A client for accessing the hedera_mirror API.
"""
def __init__(
self,
version=None,
env=None,
environ=None
):
environ = environ or os.environ
self.hedera_mirror_version = version or environ.get('hedera_mirror_VERSION')
self.env = env or environ.get('hedera_mirror_ENV')
base_url = {
"mainnet": 'https://mainnet-public.mirrornode.hedera.com/api',
"testnet": 'https://testnet.mirrornode.hedera.com/api',
"previewnet": "https://previewnet.mirrornode.hedera.com/api/v1/transactions/api"
}
try:
self.base_url = base_url[self.env.strip().lower()]
except AttributeError:
raise Exception("Use 'mainnet', 'testnet' or 'previewnet' as env")
# Domains
self._account = None
def request(self, method, base_url, domain, version, profile_id=None,
domain_id=None, domain_action=None, params=None, data=None, headers=None, auth=None):
headers = headers or {}
params = params or {}
method = method.upper()
path, url = PathBuilder(base_url=base_url, domain=domain, version=version, profile_id=profile_id,
domain_id=domain_id, domain_action=domain_action, params=params).build()
print(f'Endpoint (url): \n{url}\n\n')
api = APIRequester(url = url)
response = api.get()
print(
f'Response:\nStatus:\n{response.status_code}\nJson Response:\n{response.json()}'
)
json_response = response.json()
return {
"status": response.status_code,
"json": json_response
}
@property
def account(self):
"""
Access the did_sdk Account API
"""
if self._account is None:
from did_sdk.rest.account import Account
self._account = Account(self, self.base_url, 'account', self.hedera_mirror_version)
return self._account
What have we just done here?
create_params:
This is a little piece of code that takes parameters and converts them to a url parameter string. This is used to handle the API filtering.
PathBuilder:
This class is important. It takes a handful of arguments and creates a url that is called by the request package.
The aim here is to construct a url that looks something like this:
https://testnet.mirrornode.hedera.com/api/v1/accounts?account.id=gte:0.0.25
APIRequester:
This is what makes the api request (using requests).
Client:
This is our client for accessing the hedera_mirror API. This class strings everything together.
And that is it! Easy, right? Let's see if it works.
Test the SDK:
Open a new terminal and fire up the virtual env.
Open a python interpreter.
Use the following code to create a client to access the API.
from did_sdk.rest import Client
client = Client(version="v1", env="testnet")
Now make some API calls.
client.account.get()
client.account.get(profile_id="0.0.25")
client.account.get(params={"gte":"0.0.60"})
client.account.get(params={"lte":"0.0.30"})
If everything went well, you will now see the API results in the terminal.
Congratulations, you have created your first SDK. You can go ahead and flesh out the SDK to cover more end points...Have some fun with it.
Start typing and press Enter to search