guile-json icon indicating copy to clipboard operation
guile-json copied to clipboard

Add scm->value and value->scm specifications to define-json-type

Open vintnes opened this issue 1 year ago • 2 comments

Hi Aleix. Thank you for this solid library I use daily.

It's kind of painful when a JSON type with a nested record type needs to implement some value conversion.

Example

(use-modules (json))

(define simplified-real-world-json
"{\"initializationDate\":\"2018-06-19T08:13:04.29+02:00\",\"product\":\"ICE\",\"trainNumber\":\"369\",\"serviceId\":\"1529131014\",\"wagons\":[{\"group\":0,\"type\":\"TRIEBKOPF\",\"id\":\"938054015830\",\"wagonNumber\":null,\"status\":\"OFFEN\"}]}")

(define-json-type <manifest>
  (initialization-date "initializationDate")
  (product)
  (train-number "trainNumber")
  (service-id "serviceId")
  (wagons "wagons" #(<wagon>)))

(define-json-type <wagon>
  (group) (type) (id) (number "wagonNumber") (status))

Now let's say we'd like to operate on the train number (simpler than the date for illustration purposes), delivered to us by the grace of German engineering in string format. Reformatting according to define-json-mapping is a little tedious but overall worth the convenience/granularity tradeoff in my opinion. The painful part is that we also have to manually map any nested records, which isn't related to the problem we're working on.

(use-modules (ice-9 match))

(define wagon-converter
  (match-lambda (#((= scm->wagon wagons) ...) wagons)
                (((= wagon->scm wagons) ...) (list->vector wagons))))

(define-json-mapping <manifest> manifest manifest?
  json->manifest <=> manifest->json
  (initialization-date manifest-initialization-date "initializationDate")
  (product manifest-product)
  (train-number manifest-train-number "trainNumber" string->number number->string)
  (service-id manifest-service-id "serviceId")
  (wagons manifest-wagons "wagons" wagon-converter wagon-converter))

(call-with-input-string simplified-real-world-json json->manifest)

Am I just missing something simple? Is there any reason why define-json-type can't support the scm->value and value->scm field specifications? Have you considered using keywords over positional parameters, or would you be open to that change in the future? Thanks again for your support.

vintnes avatar Mar 26 '23 18:03 vintnes

hi @vintnes ! Yes, it's definitely a little bit more painful. I added define-json-type to be able to define simple JSON objects in a very simple way, but when it comes to flexibility you run into the issue you are having now. It might be worth adding keyword arguments there as you suggest, for example:

(define-json-type <manifest>
  (initialization-date "initializationDate")
  (product)
  (train-number "trainNumber" #:encode number->string #:decode string->number)
  (service-id "serviceId")
  (wagons "wagons" #(<wagon>)))

aconchillo avatar Mar 29 '23 20:03 aconchillo

I don't have much time lately but I think it would be a nice addition. I'll see if I find some time soon.

aconchillo avatar Mar 29 '23 20:03 aconchillo