• בלוג
  • איך להוציא בקשת HTTP ב Clojure

איך להוציא בקשת HTTP ב Clojure

04/06/2023

קלוז'ר מאוד נדיבה בפונקציות שקשורות לנתונים ועיבוד מידע ברמה שמזכירה את רובי, אבל בכל מה שקשור ל"בטריות" הן הושארו בחוץ - אין דרך מובנית בשפה לקרוא JSON, אין מנגנון log מובנה בשפה וגם, במה שקשור לפוסט שלנו, אין דרך מובנית בשפה לשלוח בקשת HTTP.

התפיסה של קלוז'ר היא שאלה דברים שאמורים להיות מפותחים בספריות הרחבה או להשתמש ביכולות של השפה המארחת, כלומר ב JVM או בדפדפן.

לכן אפשר לתרגם את השאלה איך להוציא בקשת HTTP בקלוז'ר לשאלות המקבילות בשפות המארחות - "איך להוציא בקשת HTTP ב Java", ו"איך להוציא בקשת HTTP ב JavaScript מתוך דפדפן". בואו נראה את התשובות ואיך הן מתורגמות לקלוז'ר.

1. איך להוציא בקשת HTTP ב Clojure שרץ ב JVM

באופן רגיל תוכנית קלוז'ר רצה בתוך המכונה הוירטואלית של Java, ולכן בקשת HTTP של קלוז'ר תצטרך להשתמש בקלאסים המתאימים מ Java. התוכנית הבאה ב Java שולחת בקשת HTTP ומדפיסה את התשובה:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://dummyjson.com/products"))
      .build();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
  }
}

ואת זה אפשר בקלות לתרגם לקלוז'ר:

(import
  (java.net URI)
  (java.net.http HttpResponse$BodyHandlers)
  (java.net.http HttpClient HttpRequest))

(defn -main []
  (let [client (HttpClient/newHttpClient)
        request (.build (HttpRequest/newBuilder
                          (URI/create "https://dummyjson.com/products")))
        response (.send client request (HttpResponse$BodyHandlers/ofString))]
    (println (.body response))))

(-main)

2. איך להוציא בקשת HTTP ב ClojureScript

ומה בנוגע ל ClojureScript? הוא רץ בתוך דפדפן ולכן הבסיס שלנו יהיה שליחת בקשת HTTP מתוך JavaScript. הקוד נראה כך:

async function main() {
  const res = await fetch("https://dummyjson.com/products");
  const data = await res.json();
  console.log(data);
}

main();

אז אומנם אין await מובנה ב ClojureScript אבל עדיין אפשר להשתמש ב Promises עם then ולקבל את אותו הקוד בגירסת קלוז'ר:

(->
 (js/fetch "https://dummyjson.com/products")
 (.then #(.json %))
 (.then #(js->clj %))
 (.then #(println %)))

היתרון של גירסת ה ClojureScript הוא שגם קיבלנו פיענוח של ה JSON (בניגוד ל Java שהחזיר רק מחרוזת). הפקודה js->clj הפכה את מבנה הנתונים למפה קלוז'רית ולכן אפשר לעדכן את הקוד כדי להדפיס רק שדה מסוים ממנו, למשל רק את רשימת המוצרים:

(->
 (js/fetch "https://dummyjson.com/products")
 (.then #(.json %))
 (.then #(js->clj %))
 (.then #(println (get % "products"))))

מובן שלבחירה של קלוז'ר להסתמך על הסביבה המארחת יש יתרונות וחסרונות, אבל הדבר החשוב לנו כמתכנתים הוא להכיר את הבחירה הזאת ולזכור איזה סוג פיתרונות כדאי לחפש בקלוז'ר עצמה ואיזה פיתרונות עדיף לנו לחפש בסביבה המארחת.