Search code examples
raemjcrslinghttr

How to POST JSON to AEM JCR from R?


I've been beating my head on this for, oh, three weeks now, and I would really appreciate any tips/hints/ideas. I know the following isn't reproducible (I think, but then again, my knowledge of AEM JCR is limited), but hopefully someone will see something obvious I'm doing wrong. Okay, I'm simply trying to create a basic top-level node in AEM from R. I'm using httr, and I'll include the JSON and the R code:

The JSON:

{"content":{"jcr:content":{"cq:designPath":["/etc/designs/myorg"],"cq:template":["/apps/myorg/templates/mynode"],"sling:resourceType":["myorg/components/pages/mynode"],"hideInNav":["true"],"jcr:primaryType":["cq:PageContent"],"jcr:title":["Node Name"]}}}

The R code:

aem_stage_url <- "http://aem-stage-xxxx.mydomain.com:4502/content/myorganization/en?:contentType=json&:nameHint=mynode&:operation=import"

safe_POST <- purrr::safely(httr::POST)

aem_res <- safe_POST(aem_stage_url, 
                     add_headers("Content-Type" = "application/x-www-form-urlencoded"),
                     authenticate("user" = "myuser", "password" = "mypassword", type = "basic"),
                     body = json_str,
                     encode = "form",
                     verbose(data_out = TRUE, info = TRUE)
)

The verbose output from httr:

    *  Connected to aem-stage-xxxx.myorg.com (35.167.72.242) port 4502 (#18)
*  Server auth using Basic with user 'myuser'
-> POST /content/myorg/en?:contentType=json&:nameHint=mynode&:operation=import HTTP/1.1
-> Host: aem-stage-xxxx.myorg.com:4502
-> Authorization: Basic KEY==
-> User-Agent: libcurl/7.47.0 r-curl/0.9.3 httr/1.3.1
-> Accept-Encoding: gzip, deflate
-> Cookie: cq-authoring-mode=TOUCH
-> Accept: application/json, text/xml, application/xml, */*
-> Content-Type: application/x-www-form-urlencoded
-> Content-Length: 281
-> 
>> {"content":{"jcr:content":{"cq:designPath":["/etc/designs/myorg"],"cq:template":["/apps/myorg/templates/mynode"],"sling:resourceType":["myorg/components/pages/mynode"],"hideInNav":["true"],"jcr:primaryType":["cq:PageContent"],"jcr:title":["Node Name"]}}}

*  upload completely sent off: 281 out of 281 bytes
<- HTTP/1.1 412 Precondition Failed
<- Date: Wed, 03 Jan 2018 07:35:44 GMT
<- X-Content-Type-Options: nosniff
<- X-Frame-Options: SAMEORIGIN
<- Content-Type: application/json; charset=UTF-8
<- Content-Length: 217
<- 
*  Connection #18 to host aem-stage-xxxx.myorg.com left intact

I suspect that I'm either missing a parameter in my URL, or that my JSON is malformed. I've gotten this to work in Postman, but getting it to work in R is stymying me. Any ideas?


Solution

  • So after continuing to bang my head on this for another couple days, I finally figured out how to make this work. I found that I had to have 1) the correct URL, 2) the correct parameters in that URL, 3) correctly formatted (namely, unboxed) JSON, 4) the correct headers in my post, and 5) the JSON correctly encoded.

    Here's what finally worked...

    The JSON I was trying to send:

    {"jcr:content":{"cq:designPath":"/etc/designs/myorg","cq:template":"/apps/myorg/templates/mynode","sling:resourceType":"myorg/components/pages/mynode","hideInNav":"true","jcr:primaryType":"cq:PageContent","jcr:title":"Node Name"}, "jcr:primaryType": "cq:Page"}
    

    ...Needed to be:

    :content={"jcr:content":{"cq:designPath":"/etc/designs/myorg","cq:template":"/apps/myorg/templates/mynode","sling:resourceType":"myorg/components/pages/mynode","hideInNav":"true","jcr:primaryType":"cq:PageContent","jcr:title":"Node Name"}, "jcr:primaryType": "cq:Page"}& =
    

    Note (#1) the JSON format must be unboxed. So in jsonlite this is jsonlite::toJSON(aem_json, auto_unbox = TRUE)

    Note (#2) the :content= at the beginning, and the & = at the end. For some reason these are absolutely essential for getting AEM to consume what you're sending.

    The correct JSON needed to be correctly encoded:

    aem_json_enc <- URLencode(aem_json_final)
    

    The URL needed to be of this form:

    aem_stage_url <- 'http://aem-stage-author.myorg.com:4502/content/myorg/en?:contentType=json&:name=node-name&:operation=import&:replace=true'
    

    And the R code for the actual POST:

    safe_POST <- purrr::safely(httr::POST)
    
    aem_res <- safe_POST(aem_stage_url, 
                         add_headers("Content-Type" = "application/x-www-form-urlencoded",
                                     'Authorization: Basic <mykey>'),
                         authenticate("user" = "node-listener-aem", "password" = "<my_password>", type = "basic"),
                         body = aem_json_enc, # the body is the encoded json with the extra stuff on the front and the back
                         verbose(data_out = TRUE, info = TRUE)
    )
    

    Note that the Content-Type must be application/x-www-form-urlencoded

    I hope that this answer helps some of you who are attempting to work with AEM from R.