I’ve been messing around with the new HTTP outcalls feature and the examples that I found online, mainly the Coding with @kpeacockproxy sample project.
I have a question – when my HTTP call gets a response in JSON, such as this one, is there a way in Motoko to assign it into a variable typed as this one?
type User = {
userId : Nat8;
id : Nat8;
title : Text;
body : Text;
};
Or do I have to parse values from the JSON as a text manually as is presented in this sample code?
I have encountered the same problem without having found a ready-made solution. So I wrote a parser that allows me to recover the value of a json object. It works in my use case but you can use it as inspiration :
public func parseValue(json : Text, obj : Text) : async Text {
var r : Text = "";
let b : Buffer.Buffer<Text> = Buffer.Buffer(1);
for (e in Text.split(json, #text "[")) {
if (Text.contains(e, #text obj)) {
for (o : Text in Text.split(e, #text "{")) {
var j : Text = Text.replace(o, #text "}", "");
j := Text.replace(j, #text "]", "");
if (Text.endsWith(j, #text ",")) {
j := Text.trimEnd(j, #text ",");
};
for (f : Text in Text.split(j, #text ",")) {
if (Text.contains(f, #text obj)) {
for (t : Text in Text.split(f, #text ":")) {
switch (Text.contains(t, #text obj)) {
case (false) {
b.add(Text.replace(t, #text "\"", ""));
};
case (true) {};
};
};
};
};
};
};
};
r := b.get(b.size() - 1);
return r;
};
Thank you @Severin! I tried to work this module out and I can now confirm that this allows me to parse JSON object from text and then access individual values inside and construct the User type. It still requires more writing than I expected and took me some time to work this out. But I guess this is the best available option for now.
Thank you @Kyan, this is also interesting. I was aware of that I could parse it manually, I guess was just lazy to do it myself and was looking for easier way :). Thanks a lot for sharing this.
Cross-posting visibility, and because I think it’s such an elegant solution:
import serdeJson "mo:serde/JSON";
type User = {
name: Text;
id: Nat;
};
let blob = serdeJson.fromText("{\"name\": \"bar\", \"id\": 112}");
let user : ?User = from_candid(blob);
assert user == ?{ name = "bar"; id = 112 };