1 module coinmarketcap_api.coinmarketcap_api; 2 3 import std.array: join; 4 import std.conv: to; 5 import std.json; 6 import std.net.curl; 7 import std.uri; 8 import std.zlib; 9 10 class CoinmarketcapAPI { 11 protected: 12 const string BASE_URL = "https://pro-api.coinmarketcap.com"; 13 HTTP client; 14 string url; 15 string versionApi; 16 string _version = "0.1.1"; 17 18 19 public: 20 21 this (in string apiKey, in string versionApi = "v1") { 22 this.versionApi = versionApi; 23 this.url = BASE_URL ~ "/" ~ versionApi ~ "/"; 24 25 this.client = HTTP(); 26 client.method = HTTP.Method.get; 27 client.addRequestHeader("X-CMC_PRO_API_KEY", apiKey); 28 client.addRequestHeader("Accept", "application/json"); 29 client.addRequestHeader("Accept-Charset", "UTF-8"); 30 client.addRequestHeader("Accept-Encoding", "deflate, gzip"); 31 client.addRequestHeader("User-Agent", "coinmarketcap-d-api/"~this._version); 32 } 33 34 HTTP getClient () { 35 return client; 36 } 37 38 39 /** 40 * Get a paginated list of all cryptocurrencies with latest market data 41 42 * @param {int=} Return results from rank start and above 43 * @param {int=} Only returns limit number of results [1..5000] 44 * @param {string[]=} Return info in terms of another currency 45 * @param {string=} Sort results by the options at https://pro.coinmarketcap.com/api/v1#operation/getV1CryptocurrencyListingsLatest 46 * @param {string=} Direction in which to order cryptocurrencies ("asc" | "desc") 47 * @param {string=} Type of cryptocurrency to include ("all" | "coins" | "tokens") 48 * 49 * @example 50 * getList(1, 10) 51 * getList(1, 10, ["EUR", "USD"]) 52 */ 53 auto getList (T = string)( 54 in int start = 1, in int limit = 100, in string[] convert = ["USD"], 55 in string sort = "market_cap", in string sortDir = "", in string cryptocurrencyType = "all" 56 ) { 57 string[string] data = [ 58 "start": to!string(start), 59 "limit": to!string(limit), 60 "convert": join(convert, ","), 61 "sort": sort, 62 "cryptocurrency_type": cryptocurrencyType 63 ]; 64 if (sortDir != "") data["sort_dir"] = sortDir; 65 return request!T("cryptocurrency/listings/latest", data); 66 } 67 68 69 /** 70 * Get static metadata for one or more cryptocurrencies 71 * 72 * @param {string|string[]|int|int[]=} One or more comma separated cryptocurrency IDs or symbols 73 * 74 * @example 75 * metadata(2); 76 * metadata(1, 2); 77 * metadata([1, 2]); 78 * metadata("BTC,ETH"); 79 * metadata("BTC", "ETH"); 80 * metadata(["BTC", "ETH"]); 81 */ 82 auto getMetadata (T = string)(in int[] ids) { 83 return request!T("cryptocurrency/info", ["symbol", join(to!(string[])(ids), ",")]); 84 } 85 auto getMetadata (T = string)(in int[] ids...) { 86 return request!T("cryptocurrency/info", ["symbol", join(to!(string[])(ids), ",")]); 87 } 88 auto getMetadata (T = string)(in string[] symbols) { 89 return request!T("cryptocurrency/info", ["symbol": join(symbols, ",")]); 90 } 91 auto getMetadata (T = string)(in string[] symbols...) { 92 return request!T("cryptocurrency/info", ["symbol": join(symbols, ",")]); 93 } 94 95 96 /** 97 * Returns a paginated list of all cryptocurrencies by CoinMarketCap ID 98 * 99 * @param {string=} active or inactive coins 100 * @param {int=} Optionally offset the start (1-based index) of the paginated list of items to return. 101 * @param {int=} Optionally specify the number of results to return 102 * @param {string=|string[]} Optionally pass a comma-separated list of cryptocurrency symbols to return CoinMarketCap IDs for. 103 * If this option is passed, other options will be ignored. 104 * 105 * @example 106 * getMap(); 107 * getMap("active", 1, 10); 108 * getMap("active", 1, 1, ["BTC", "ETH"]); 109 */ 110 auto getMap (T = string)(in string status = "active", in int start = 1, in int limit = 100, in string symbols = "") { 111 auto data = [ 112 "listing_status": status, 113 "start": to!string(start), 114 "limit": to!string(limit) 115 ]; 116 if (symbols != "") data["symbol"] = symbols; 117 return request!T("cryptocurrency/map", data); 118 } 119 auto getMap (T = string)(in string status, in int start, in int limit, in string[] symbols) { 120 121 return getMap!T(status, start, limit, join(symbols, ",")); 122 } 123 124 125 /** 126 * Get latest market quote for 1 or more cryptocurrencies 127 128 * @param {string|string[]|int|int[]} One or more comma separated cryptocurrency symbols 129 * @param {string|string[]=} Return quotes in terms of another currency 130 * 131 * @example 132 * getQuotes("BTC") 133 * getQuotes(1) 134 * getQuotes("BTC,ETH", "EUR") 135 * getQuotes(["BTC", "ETH"], ["EUR, "USD"]) 136 * getQuotes(1, ["EUR, "USD"]) 137 * getQuotes([1, 2], ["EUR, "USD"]) 138 */ 139 auto getQuotes (T = string)(in string symbol, in string convert = "USD") { 140 auto data = [ 141 "symbol": symbol, 142 "convert": convert 143 ]; 144 return request!T("cryptocurrency/quotes/latest", data); 145 } 146 auto getQuotes (T = string)(in string symbol, in string[] convert) { 147 return getQuotes!T(symbol, join(convert, ",")); 148 } 149 auto getQuotes (T = string)(in string[] symbols, in string convert) { 150 return getQuotes!T(join(symbols, ","), convert); 151 } 152 auto getQuotes (T = string)(in string[] symbols, in string[] convert) { 153 return getQuotes!T(join(symbols, ","), join(convert, ",")); 154 } 155 156 auto getQuotes (T = string)(in int id, in string convert = "USD") { 157 auto data = [ 158 "id": to!string(id), 159 "convert": convert 160 ]; 161 return request!T("cryptocurrency/quotes/latest", data); 162 } 163 auto getQuotes (T = string)(in int id, in string[] convert) { 164 return getQuotes!T(to!string(id), join(convert, ",")); 165 } 166 auto getQuotes (T = string)(in int[] ids, in string convert) { 167 return getQuotes!T(join(to!(string[])(ids), ","), convert); 168 } 169 auto getQuotes (T = string)(in int[] ids, in string[] convert) { 170 return getQuotes!T(join(to!(string[])(ids), ","), join(convert, ",")); 171 } 172 173 174 /** 175 * Get global information 176 * 177 * @param {string|string[]=} Return quotes in terms of another currency 178 * 179 * @example 180 * getGlobal("ETH") 181 * getGlobal(["ETH", "LTC"]) 182 */ 183 auto getGlobal (T = string)(in string convert = "USD") { 184 return request!T("global-metrics/quotes/latest", ["convert": convert]); 185 } 186 auto getGlobal (T = string)(in string[] convert) { 187 return getGlobal!T(join(convert, ",")); 188 } 189 190 191 string paramsToStr (in string[string] params) { 192 string[] ar; 193 foreach(key, val; params) { 194 ar ~= key ~ "=" ~ val.encode; 195 } 196 return join(ar, "&"); 197 } 198 199 T request (T = string)(in string method, in string[string] params) { 200 return request!T(method, paramsToStr(params)); 201 } 202 203 T request (T: JSONValue)(in string method, in string[string] params) { 204 return request!T(method, paramsToStr(params)); 205 } 206 207 T request (T = string)(in string method, in string param = "") { 208 bool isGzip = false; 209 ubyte[] result = []; 210 UnCompress decompressor = new UnCompress; 211 212 if (param == "") client.url = this.url ~ method; 213 else client.url = this.url ~ method ~ "?" ~ param; 214 215 client.onReceiveHeader = (in char[] key, in char[] value) { 216 string v = cast(string)value; 217 if (cast(string)key == "content-encoding" && (v == "gzip" || v == "deflate")) isGzip = true; 218 }; 219 client.onReceive = (ubyte[] data) 220 { 221 result ~= data; 222 return data.length; 223 }; 224 client.perform(); 225 return cast(string) (isGzip ? decompressor.uncompress(result) : result); 226 } 227 228 T request (T: JSONValue)(in string method, in string param = "") { 229 return parseJSON(request(method, param)); 230 } 231 }