Error with set parObj = {}.%FromJSON(%request.Content.ReadLineIntoStream())
I try to test our REST/JSON (POST) services,where queryparametres are in content as json and the answer in contet is also as json.
This is my testClient:
Class XXX.RESTClient Extends %RegisteredObject
{
ClassMethod TestXXX()
{
#dim tRequest As %Net.HttpRequest = ##class(%Net.HttpRequest).%New()
set tRequest.ContentType="application/json"
s json=##class(%ZEN.proxyObject).%New()
s json.x="XXX"
d ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(.jsonStream,json)
set jsonText=jsonStream.Read(jsonStream.Size)
set tSC=tRequest.EntityBody.Write(jsonText)
set tSC = tRequest.Post("http://server:57776/csp/XXX/testXXX")
do tRequest.HttpResponse.OutputToDevice()
}
}
in dispatchClass:
ClassMethod testXXX() As %Status
{
#dim tStatus As %Status = $$$OK
#dim parObj As %DynamicAbstractObject = {}
#dim dynObj As %DynamicAbstractObject = {}
set $ZT="ERROR"
goto:'..%securityCheck(.tStatus,parObj) DONE
DONE ;
do ..%logout(.tStatus,dynObj)
quit tStatus
ERROR ;
set tStatus = $$$ERROR($$$CacheError,$ZE)
do BACK^%ETN
goto DONE
}
ClassMethod %securityCheck(ByRef pStatus As %Status, parObj As %DynamicAbstractObject) As %Boolean
{
set pStatus = $$$OK
set $ZT="ERROR"
#dim %request As %CSP.Request
if %request.ContentType'=..#CONTENTTYPE {
set pStatus=$$$ERROR($$$GeneralError,"Wrong ContentType")
goto DONE
}
if '$IsObject(%request.Content) {
set pStatus=$$$ERROR($$$GeneralError,"No Content")
goto DONE
}
/*
//THIS WRITES OK { "x":"XXX"}
do %request.Content.Rewind()
Set fstream=##class(%FileBinaryStream).%New()
do fstream.LinkToFile("content.txt")
do %request.Content.Rewind()
do fstream.CopyFrom(%request.Content)
do fstream.%Save()
AND THIS IS OK (the same):
do %request.Content.OutputToDevice()
*/
//Content is type of %CSP.BinaryStream
do %request.Content.Rewind()
set parObj = {}.%FromJSON(%request.Content.ReadLineIntoStream()) //<== THERE I GET THE ERROR
do %request.Content.Rewind()
***
goto DONE
}
DONE ;
quit $$$ISOK(pStatus)
ERROR ;
set pStatus = $$$ERROR($$$CacheError,$ZE)
do BACK^%ETN
goto DONE
}
THIS IS THE ERROR
{"status":{"koodi":"0","selite":"Cache error: <THROW>%FromJSON+37^%Library.DynamicAbstractObject.1 *%Exception.General Premature end of data 12 Line 1 Offset 1 "}}{
"errors":[ {
"code":5002,
"domain":"%ObjectErrors",
"error":"ERROR #5002: Cache error: <THROW>%FromJSON+37^%Library.DynamicAbstractObject.1 *%Exception.General Premature end of data 12 Line 1 Offset 1 ",
"id":"CacheError",
"params":["<THROW>%FromJSON+37^%Library.DynamicAbstractObject.1 *%Exception.General Premature end of data 12 Line 1 Offset 1 "
]
}
],
"summary":"ERROR #5002: Cache error: <THROW>%FromJSON+37^%Library.DynamicAbstractObject.1 *%Exception.General Premature end of data 12 Line 1 Offset 1 "
}
WRC told Content is type on %CSP.Stream, not binaryStream. True, if you read %CSP.request, but this works in another application. And in errorlog Content is told to be binary stream.
+----------------- swizzled references ---------------
| i%Content = "3@%CSP.BinaryStream"
| r%Content = ""
+-----------------------------------------------------
What is my error? How should I change this? Some changes to testClient, not service itself?
Comments
you do .ReadLineIntoStream()
doc says: https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls
This reads from the stream until it find the LineTerminator and returns this as a stream. If the stream does not contain the line terminator this can potentially be the entire stream.
and your error message: Premature end of data 12 Line 1 Offset 1
indicates that you have hit some character interpreted as line terminator after 12 characters. (rather short for JSON)
My guess: your JSON input is a multiline input with enough line terminators inside
As a consequence your JSON input is incomplete.
Suggested workaround
- get length of your stream method SizeGet()
- read full stream ignoring line terminators using method Read(ByRef len As %Integer, ByRef sc As %Status) as %CacheString
eventually, it might be necessary to remove the line terminators before %FromJSON
Hi Robert,
According the doc, %request.content is %CSP.Steam which doesn't have Read() method.
https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls…
Any hints?
Thanks,
Shannon
OK. for some reason the most important part of the link was truncated.
I hope it doesn't hide again.
The basic mistake happens here the definition of Request
https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=%25CSP.Request
.png)
And you are right. %CSP.Stream has no Read method because ContentType tells you the true object .
As in the example:
.png)
It could have been %CSP.CharacterStream as well.
Both extend over some steps %GlobalStreamAdaptor which have all the READ, WRITE, ....methods
Just reading docs and not checking inherited methods (e.g. in Studio) is mostly misleading.
Aha, that is how "ContentType" take effect. Thanks, Robert!
I would like to suggest the doc people to make it more clear though.
You can just pass the stream directly, no need to read from it:
set parObj = {}.%FromJSON(%request.Content)