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