3

I'm having difficulty in determining what the best practices are for structuring data for calling various APIs that contain bitcoin prices. I want to be able to call multiple APIs, without duplicate code.

My initial thought was to build classes for each of the APIs I would be calling, and feed their attributes (api_id, url, and json_tree (json path I'd like to pull data from) to the BtcAPI class, and spit them out.

*Note, before reading that while BtcAPI works, the Coindesk/Bitstamp classes do not yet interact with that class. I want to ask about the way I should do this before I go to the trouble...*

Now, I'm wondering if I shouldn't make them lists, like:

coindesk = ['http://www.something.com', 'coindesk', '["time"]["updated"]']

...and just iterate through each of them. Or dicts, or any variety of other thing. What data structure is indicated here?

I am basically looking for a bit of a code review (since this code isn't working, I don't want to send it to the code review stack) and an understanding of best practices: tell me where you think I'm screwing up horribly, and what I can do to structure this data better? I'm a python and oop noob. I could do this procedurally, but it would be ugly and superfluous. I imagine I'm using classes a bit wrong, too. Insights? Help? Thank you!

Thank you!

import json
import urllib.request

#The BtcAPI class works well when you feed it static variables. It returns json.

class BtcAPI:

    def __init__(self, url, api_id):
        self.url = url
        self.api_id = api_id

    def btc_api_call(self):

        hdr = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'     }
        req = urllib.request.Request(url, headers=hdr)
        readdata = urllib.request.urlopen(req)
        json_data = readdata.read()

        json_dict = json.loads(json_data)
        return(json_dict)

class Coindesk:


    api_id = 'Coindesk'
    url = 'https://api.coindesk.com/v1/bpi/currentprice.json'               
    json_tree = json_dict['time']['updated']

    def __init__(self):

        self.current_us_price = current_us_price

class Bitstamp:


    api_id = 'Bitstamp'
    url = 'https://www.bitstamp.net/api/ticker/'               
    json_tree = json_dict['last']

    def __init__(self):

        self.current_us_price = current_us_price

coindesk_url = Coindesk()
coindeskoutput = coindesk_url.url
print(coindeskoutput)

2 Answers 2

12

If you want a generic piece of code, I would suggest that you dissociate your code and your configuration data into 2 files. This way you can manage your configuration data (URL, JSON attributes you want to retrieve) without having to modify your actual Python code. This is usually considered a good practice but it implies to manage two files instead of one so it can be a bit of a burden if you are on a very small project.

Example in your case, you can have:

  • conf.ini
  • bitcoin_api.py

conf.ini

Configuration file which would look like this:

[COINDESK]
url: https://api.coindesk.com/v1/bpi/currentprice.json
response: time.updated

[BITSTAMP]
url: https://www.bitstamp.net/api/ticker
response: last

bitcoin_api.py

Your code would look like this:

import configparser
import requests
import os


class BitcoinAPI:
    def __init__(self, API):
        config = configparser.ConfigParser()
        config.read(os.path.dirname(__file__) + '/conf.ini')
        self.url = config.get(API, 'url')
        self.attribute = config.get(API, 'response')
        self.header = {'content-type': 'application/json'}

    def get(self):
        response = requests.get(self.url, headers=self.header)
        response = response.json()

        # Browse the response to fetch only the attributes you want
        self.attribute = self.attribute.split('.')
        depth = len(self.attribute)
        for i in range(depth):
            response = response[self.attribute[i]]

        print(response)
        return response

Then you can call you class in your main script:

import bitcoin_api
result = bitcoin_api.BitcoinAPI('COINDESK').get()
result = bitcoin_api.BitcoinAPI('BITSTAMP').get()
Sign up to request clarification or add additional context in comments.

2 Comments

I've updated the answer above. It works on my side :) Please consider marking the issue solved if it helped you. Thanks
This was the most concise and useful answer. Thank you for helping me get clarity on the best way to organize this!
2

Well, the sane way to struct your code would involve super classes (inheritance) and some sort of standardisation (interfaces).

Assuming that I understand you question, you need a standard on how to request the prices from various exchanges.

So consider this structure (of course it's completely draft):

import requests

class BitcoinAPI:

    def get_price_usd(self):
        raise NotImplementedError

    @staticmethod
    def generic_unothorized_request(request_method, url, **kwargs):
        return getattr(requests, request_method)(url, **kwargs)


class CoinDesk(BitcoinAPI):

    url = 'https://api.coindesk.com/v1/bpi/currentprice.json'

    def get_price_usd(self):
        return self.generic_unothorized_request('get', url)
        # process result, bla bla


class Bitstamp(BitcoinAPI):

    def get_price_usd(self):
        # Implementation of get_price_usd for Bitstamp
        return 0.0

1 Comment

This is great. I'm going to study this, create a draft, and respond shortly. Thank you so much for putting in the effort to answer this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.