Http outcall response JSON processing in Motoko

Hello,

I’ve been messing around with the new HTTP outcalls feature and the examples that I found online, mainly the Coding with @kpeacock proxy 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?

Thanks a lot for help.

2 Likes

Some searching on the interwebz produced this link: GitHub - aviate-labs/json.mo: JSON for Motoko, but I have not tried it myself. Let us know if it works!

1 Like

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;
    };
2 Likes

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.

1 Like

Small piece of morning code with a more complex json structure :
Motoko playground - Get Json key value

4 Likes

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 };
4 Likes

Looking great! Thanks, Paul.

I’m glad you think so!

1 Like