Url Parsing in Lisp

Here’s the translation of the Go URL parsing example to Lisp, formatted in Markdown suitable for Hugo:

(ql:quickload '(:dexador :quri))

(defun main ()
  ;; We'll parse this example URL, which includes a
  ;; scheme, authentication info, host, port, path,
  ;; query params, and query fragment.
  (let ((s "postgres://user:pass@host.com:5432/path?k=v#f"))
    
    ;; Parse the URL and ensure there are no errors.
    (let ((u (quri:uri s)))
      (unless u
        (error "Failed to parse URL"))

      ;; Accessing the scheme is straightforward.
      (format t "~A~%" (quri:uri-scheme u))

      ;; User contains all authentication info
      (format t "~A:~A~%" (quri:uri-userinfo u) (quri:uri-password u))
      (format t "~A~%" (quri:uri-userinfo u))
      (format t "~A~%" (quri:uri-password u))

      ;; The Host contains both the hostname and the port,
      ;; if present.
      (format t "~A~%" (quri:uri-host u))
      (format t "~A~%" (quri:uri-port u))

      ;; Here we extract the path and the fragment after
      ;; the #.
      (format t "~A~%" (quri:uri-path u))
      (format t "~A~%" (quri:uri-fragment u))

      ;; To get query params in a string of k=v format,
      ;; use query-string. You can also parse query params
      ;; into an alist.
      (format t "~A~%" (quri:uri-query u))
      (let ((m (quri:uri-query-params u)))
        (format t "~A~%" m)
        (format t "~A~%" (cdr (assoc "k" m :test #'string=)))))))

(main)

Running our URL parsing program shows all the different pieces that we extracted:

postgres
user:pass
user
pass
host.com
5432
/path
f
k=v
(("k" . "v"))
v

This Lisp example uses the quri library to parse URLs, which provides functionality similar to Go’s net/url package. The dexador library is also loaded for potential HTTP requests, although it’s not used in this specific example.

Key differences in the Lisp version:

  1. We use quri:uri to parse the URL instead of url.Parse.
  2. The parsed URL is represented as a quri:uri object, which we can query using various accessor functions.
  3. There’s no direct equivalent to Go’s SplitHostPort, so we access host and port separately.
  4. Query parameters are parsed into an association list (alist) instead of a map.
  5. Error handling is done using Common Lisp’s condition system instead of returning an error value.

The overall structure and functionality of the program remain similar to the original Go version, demonstrating URL parsing capabilities in Common Lisp.