1 /* 2 * Copyright 2022 XXIV 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module dogapi; 17 18 import std.format: format; 19 import std.string: strip; 20 import std.json: JSONValue, parseJSON, JSONException; 21 import std.net.curl : byLineAsync, CurlException; 22 23 class DogAPIException : Exception 24 { 25 this(string message, string file = __FILE__, size_t line = __LINE__) 26 { 27 super(message, file, line); 28 } 29 } 30 31 private string getRequest(string endpoint) 32 { 33 auto response = byLineAsync(format("http://dog.ceo/api/%s", endpoint)); 34 string content = ""; 35 foreach (line; response) 36 content ~= line; 37 return content; 38 } 39 40 /** 41 * DISPLAY SINGLE RANDOM IMAGE FROM ALL DOGS COLLECTION 42 * 43 * Returns: random dog image 44 * Throws: DogAPIException on failure 45 */ 46 string randomImage() 47 { 48 try 49 { 50 auto response = getRequest("breeds/image/random"); 51 JSONValue data = parseJSON(response); 52 if (data["status"].str != "success") 53 { 54 throw new Exception(data["message"].str); 55 } 56 else 57 { 58 return data["message"].str; 59 } 60 } 61 catch (CurlException ex) 62 { 63 throw new DogAPIException(ex.msg); 64 } 65 catch (JSONException ex) 66 { 67 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 68 } 69 catch (Exception ex) 70 { 71 throw new DogAPIException(ex.msg); 72 } 73 } 74 75 /** 76 * DISPLAY MULTIPLE RANDOM IMAGES FROM ALL DOGS COLLECTION 77 * 78 * Params: 79 * imagesNumber = number of images 80 * Returns: multiple random dog image `NOTE` ~ Max number returned is 50 81 * Throws: DogAPIException on failure 82 */ 83 string[] multipleRandomImages(byte imagesNumber) 84 { 85 try 86 { 87 auto response = getRequest(format("breeds/image/random/%d", imagesNumber)); 88 JSONValue data = parseJSON(response); 89 if (data["status"].str != "success") 90 { 91 throw new Exception(data["message"].str); 92 } 93 else 94 { 95 string[] list = []; 96 foreach (i; data["message"].array) 97 { 98 list ~= i.str; 99 } 100 return list; 101 } 102 } 103 catch (CurlException ex) 104 { 105 throw new DogAPIException(ex.msg); 106 } 107 catch (JSONException ex) 108 { 109 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 110 } 111 catch (Exception ex) 112 { 113 throw new DogAPIException(ex.msg); 114 } 115 } 116 117 /** 118 * RANDOM IMAGE FROM A BREED COLLECTION 119 * 120 * Params: 121 * breed = breed name 122 * Returns: random dog image from a breed, e.g. hound 123 * Throws: DogAPIException on failure 124 */ 125 string randomImageByBreed(string breed) 126 { 127 try 128 { 129 auto response = getRequest(format("breed/%s/images/random", strip(breed))); 130 JSONValue data = parseJSON(response); 131 if (data["status"].str != "success") 132 { 133 throw new Exception(data["message"].str); 134 } 135 else 136 { 137 return data["message"].str; 138 } 139 } 140 catch (CurlException ex) 141 { 142 throw new DogAPIException(ex.msg); 143 } 144 catch (JSONException ex) 145 { 146 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 147 } 148 catch (Exception ex) 149 { 150 throw new DogAPIException(ex.msg); 151 } 152 } 153 154 /** 155 * MULTIPLE IMAGES FROM A BREED COLLECTION 156 * 157 * Params: 158 * breed = breed name 159 * imagesNumber = number of images 160 * Returns: multiple random dog image from a breed, e.g. hound 161 * Throws: DogAPIException on failure 162 */ 163 string[] multipleRandomImagesByBreed(string breed, long imagesNumber) 164 { 165 try 166 { 167 auto response = getRequest(format("breed/%s/images/random/%d", strip(breed), imagesNumber)); 168 JSONValue data = parseJSON(response); 169 if (data["status"].str != "success") 170 { 171 throw new Exception(data["message"].str); 172 } 173 else 174 { 175 string[] list = []; 176 foreach (i; data["message"].array) 177 { 178 list ~= i.str; 179 } 180 return list; 181 } 182 } 183 catch (CurlException ex) 184 { 185 throw new DogAPIException(ex.msg); 186 } 187 catch (JSONException ex) 188 { 189 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 190 } 191 catch (Exception ex) 192 { 193 throw new DogAPIException(ex.msg); 194 } 195 } 196 197 /** 198 * ALL IMAGES FROM A BREED COLLECTION 199 * 200 * Params: 201 * breed = breed name 202 * Returns: an array of all the images from a breed, e.g. hound 203 * Throws: DogAPIException on failure 204 */ 205 string[] imagesByBreed(string breed) 206 { 207 try 208 { 209 auto response = getRequest(format("breed/%s/images", strip(breed))); 210 JSONValue data = parseJSON(response); 211 if (data["status"].str != "success") 212 { 213 throw new Exception(data["message"].str); 214 } 215 else 216 { 217 string[] list = []; 218 foreach (i; data["message"].array) 219 { 220 list ~= i.str; 221 } 222 return list; 223 } 224 } 225 catch (CurlException ex) 226 { 227 throw new DogAPIException(ex.msg); 228 } 229 catch (JSONException ex) 230 { 231 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 232 } 233 catch (Exception ex) 234 { 235 throw new DogAPIException(ex.msg); 236 } 237 } 238 239 /** 240 * SINGLE RANDOM IMAGE FROM A SUB BREED COLLECTION 241 * 242 * Params: 243 * breed = breed name 244 * subBreed = sub_breed name 245 * Returns: random dog image from a sub-breed, e.g. Afghan Hound 246 * Throws: DogAPIException on failure 247 */ 248 string randomImageBySubBreed(string breed, string subBreed) 249 { 250 try 251 { 252 auto response = getRequest(format("breed/%s/%s/images/random", strip(breed), strip(subBreed))); 253 JSONValue data = parseJSON(response); 254 if (data["status"].str != "success") 255 { 256 throw new Exception(data["message"].str); 257 } 258 else 259 { 260 return data["message"].str; 261 } 262 } 263 catch (CurlException ex) 264 { 265 throw new DogAPIException(ex.msg); 266 } 267 catch (JSONException ex) 268 { 269 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 270 } 271 catch (Exception ex) 272 { 273 throw new DogAPIException(ex.msg); 274 } 275 } 276 277 /** 278 * MULTIPLE IMAGES FROM A SUB-BREED COLLECTION 279 * 280 * Params: 281 * breed = breed name 282 * subBreed = sub_breed name 283 * imagesNumber = number of images 284 * Returns: multiple random dog images from a sub-breed, e.g. Afghan Hound 285 * Throws: DogAPIException on failure 286 */ 287 string[] multipleRandomImagesBySubBreed(string breed, string subBreed, long imagesNumber) 288 { 289 try 290 { 291 auto response = getRequest(format("breed/%s/%s/images/random/%d", strip(breed), strip(subBreed), imagesNumber)); 292 JSONValue data = parseJSON(response); 293 if (data["status"].str != "success") 294 { 295 throw new Exception(data["message"].str); 296 } 297 else 298 { 299 string[] list = []; 300 foreach (i; data["message"].array) 301 { 302 list ~= i.str; 303 } 304 return list; 305 } 306 } 307 catch (CurlException ex) 308 { 309 throw new DogAPIException(ex.msg); 310 } 311 catch (JSONException ex) 312 { 313 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 314 } 315 catch (Exception ex) 316 { 317 throw new DogAPIException(ex.msg); 318 } 319 } 320 321 /** 322 * LIST ALL SUB-BREED IMAGES 323 * 324 * Params: 325 * breed = breed name 326 * subBreed = sub_breed name 327 * Returns: an array of all the images from the sub-breed 328 * Throws: DogAPIException on failure 329 */ 330 string[] imagesBySubBreed(string breed, string subBreed) 331 { 332 try 333 { 334 auto response = getRequest(format("breed/%s/%s/images", strip(breed), strip(subBreed))); 335 JSONValue data = parseJSON(response); 336 if (data["status"].str != "success") 337 { 338 throw new Exception(data["message"].str); 339 } 340 else 341 { 342 string[] list = []; 343 foreach (i; data["message"].array) 344 { 345 list ~= i.str; 346 } 347 return list; 348 } 349 } 350 catch (CurlException ex) 351 { 352 throw new DogAPIException(ex.msg); 353 } 354 catch (JSONException ex) 355 { 356 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 357 } 358 catch (Exception ex) 359 { 360 throw new DogAPIException(ex.msg); 361 } 362 } 363 364 /** 365 * LIST ALL BREEDS 366 * 367 * Returns: associative array of all the breeds as keys and sub-breeds as values if it has 368 * Throws: DogAPIException on failure 369 */ 370 string[][string] breedsList() 371 { 372 try 373 { 374 auto response = getRequest("breeds/list/all"); 375 JSONValue data = parseJSON(response); 376 if (data["status"].str != "success") 377 { 378 throw new Exception(data["message"].str); 379 } 380 else 381 { 382 string[][string] list; 383 foreach (k, v; data["message"].object) 384 { 385 string[] val = []; 386 foreach (value; v.array) 387 val ~= value.str; 388 list[k] = val; 389 } 390 return list; 391 } 392 } 393 catch (CurlException ex) 394 { 395 throw new DogAPIException(ex.msg); 396 } 397 catch (JSONException ex) 398 { 399 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 400 } 401 catch (Exception ex) 402 { 403 throw new DogAPIException(ex.msg); 404 } 405 } 406 407 /** 408 * LIST ALL SUB-BREEDS 409 * 410 * Params: 411 * breed = breed name 412 * Returns: an array of all the sub-breeds from a breed if it has sub-breeds 413 * Throws: DogAPIException on failure 414 */ 415 string[] subBreedsList(string breed) 416 { 417 try 418 { 419 auto response = getRequest(format("breed/%s/list", strip(breed))); 420 JSONValue data = parseJSON(response); 421 if (data["status"].str != "success") 422 { 423 throw new Exception(data["message"].str); 424 } 425 else 426 { 427 string[] list = []; 428 foreach (i; data["message"].array) 429 { 430 list ~= i.str; 431 } 432 if (list.length == 0) 433 throw new DogAPIException("the breed does not have sub-breeds"); 434 return list; 435 } 436 } 437 catch (CurlException ex) 438 { 439 throw new DogAPIException(ex.msg); 440 } 441 catch (JSONException ex) 442 { 443 throw new DogAPIException(format("Something went wrong while reading josn: %s", ex.msg)); 444 } 445 catch (Exception ex) 446 { 447 throw new DogAPIException(ex.msg); 448 } 449 }