#2782 Fantom based Haystack API Calls

Phillip Birch Fri 24 Jan

Im working on a fantom based webapp where it is required to perform API calls to SkySpark and am having issues with the hisRead POST op.

POST Requests API

The issue im running into is an error thrown by the SkySpark server, shown below.

sys::CastErr: java.lang.ClassCastException: fan.dict.Dict2 cannot be cast to fan.haystack.Grid at POST

My question is, whats the best way to handle this, seeing as there is no Grid type in fantom?


Obj? readSiteHis(Uri serverUrl, Str authToken, Map? siteId) {

json := Json()
Str site := siteId["id"]
Str range := siteId["range"]
SiteRec mySite := SiteRec(siteId["id"], siteId["range"])
butter   := ButterDish(Butter.churnOut())
request  := ButterRequest(Uri.fromStr(serverUrl.toStr + "api/demo/hisRead")) {  //?id=${site}&range=${range}
    it.method = "POST"
    it.headers.contentType = MimeType("application/json")
	it.headers.authorization = "BEARER authToken=${authToken}"
	it.body.json = json.toJson(mySite).toStr
response := butter.sendRequest(request)

return null


SlimerDude Fri 24 Jan

Make sure the JSON data you're POSTing conforms the Haystack JSON GRID format. It's not pretty, and very verbose, but it's what SkySpark expects. I suspect that's where problem is. (If in doubt, you could post your JSON here.)

seeing as there is no Grid type in fantom?

Yeah, writing a haystack library in native Fantom has been on my TODO list for a while. In the mean time, you could use the Java one.

brian Fri 24 Jan

Phillip, you can use the haystack.pod in your own projects outside of SkySpark if you want. It has no dependencies beyond the Fantom core pods.

Phillip Birch Sun 26 Jan

Thanks for the responses. I've been testing the SkySpark haystack.pod in my code to get the grid working and ran into an issue that im not sure how to work around. An important note, i am very new to the InStream / OutStream framework in fantom (and in general, to be honist) so im sure that im missing something simple. This is my code

gb := GridBuilder()
gb.addRow([siteId["id"], siteId["range"]])

newGrid := gb.toGrid

testBuf := Buf()
echo("Buffer Output: ${testBuf.readAllStr}")

Which when runs, outputs...

MemBuf(pos=143 size=143)
Buffer Output: 

From what i can tell, based on the MemBuf output of MemBuf(pos=143 size=143), the JsonWriter did write something, but for some reason im not getting anything from my buffer. Any ideas?

SlimerDude Mon 27 Jan

Hi Phil, very quickly...

Buffers are like arrays, but have the notion of a current position.

When you write to a buffer, data is appended to the current position (and the position subsequently updated to the end of the newly appended data).

When you read from a buffer, data is read from the current position.

So in your example. you write data to the buffer, and then readAllStr from the current position - which is at the end of the data! So an empty string is returned.

What you need to do, is move the current position to the start of the buffer before you read.

testBuf := Buf()

testBuf.seek(0)  // <-- move Buf to position 0 (the start)

echo("Buffer Output: ${testBuf.readAllStr}")

You can also use Buf.flip() which implies seek(0); it also ensures you don't read back further than you've just written by setting the Buffer's size. Just make sure you don't inadvertently call flip() twice in a row, as that has the nasty side effect of clearing the buffer! (It has cause me some pain in the past!)

There is also StrBuf which, despite it's name, has nothing to do with Buf! It is more like a mutable string, but can be written to using an OutStream. You can use it like this:

testBuf := StrBuf()

echo("Buffer Output: ${testBuf.toStr}")

As you can see, there is no need to seek or flip and the contents can be gotten by simply calling toStr.

Hope this helps,


Login or Signup to reply.