Diego Favero
Diego Favero

Reputation: 2115

GoLang WebServer sends description of param's struct on Json Response

So here is the deal : I have been working on a huge system (PHP) for a couple years, and now, I decided to give up part of heavy jobs for golang scripts.

So far, I replicated a few php scripts to a go version. Then, I am able to benchmark which option is better ( ok, I know go is faster, but I need curl or sockets to comunication, so, I have to check if it is still worth ) .

One of the scripts just generate a random code, check if this new code is already in use ( on mysql db ), if not, record the new code and return it, if is already in use, just recursive call the function again until find an exclusive code. pretty simple one.

I already had this code generator in php, so, wrote new one in go to be called as http/post with json params. Using linux terminal, I call it as

curl -H [headers] -d [jsondata] [host]

and I get back a pretty simple json

{"locator" : "XXXXXX"}

After, I wrote a simple php script to call the scripts and check how long each took to complete, something like :

<?php
public function indexAction()
    {
    $phpTime = $endPHP = $startPHP =
    $goTime = $endGO = $startGO = 0;

// my standard function already in use


    ob_start();

    $startPHP = microtime(true);
    $MyCodeLocator =  $this->container->get('MyCodeLocator')->Generate(22, 5);
    $endPHP = microtime(true);

    ob_end_clean();


    sleep(1);
    // Lets call using curl
    $data = array("comon" => "22", "lenght" => "5");
    $data_string = json_encode($data);

    ob_start();
    $startGO = microtime(true);



    $ch = curl_init('http://localhost:8888/dev/fibootkt/MyCodeGenerator');
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Content-Length: ' . strlen($data_string))
    );

    $result = curl_exec($ch);
    curl_close($ch);
    $endGO = microtime(true);
    ob_end_clean();

    $result_rr = json_decode($result);

    // tst just echo the variable in a nice way, second parameter means no kill execution
    tst($result, 1); // HERE IS MY PROBLEM, please read below
    tst($result_rr, 1); // IT SHOW NULL

    sleep(1);

// just to have params for comparision, always try by shell script
    ob_start();
    $startShell = microtime(true);;

    $exec =  "curl -H \"Content-Type: application/json\" -d '{\"comon\":\"22\"}' http://localhost:8888/dev/fibootkt/MyCodeGenerator";
    $output = shell_exec($exec);
    $endShell  = microtime(true);
    ob_end_clean();

    tst(json_decode($output),1); // here show a stdclass with correct value
    tst($output,1); // here shows a json typed string ready to be converted

    // and here it is just for show the execution time ...
    $phpTime = $endPHP - $startPHP;
    $goTime = $endGO - $startGO ;
    $shellTime = $endShell - $startShell;

    tst("php " . $phpTime, 1);
    tst("curl ". $goTime, 1);
    tst("shell " . $shellTime, 1);

And I get the results from GO : By Shell Script :

{"locator" : "DPEWX22"} 

So, this one is pretty and easy decode to a stdobj.

But, using curl, the operation is faster ! So, I want to use it. But, the curl request responds something like :

{"Value":"string","Type":{},"Offset":26,"Struct":"CodeLocatorParams","Field":"lenght"}
{"locator":"DPEWX22"}

And when I try to decode it, I get a null as result !!!

CodeLocatorParams the struct type I use in go to get the post params, as show below

so, here is my question : Why GO is returning this ? how to avoid it.

I have another similar go script which take no params and responds a similar json ( but in this case, a qrcode image path ) and it works fine !

My go function:

type CodeLocatorParams struct {
    Comon string `json:"comon"`
    Lenght int  `json:"lenght"`
}

func Generate(w http.ResponseWriter, r *http.Request) {


    data, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
    if err != nil {
        fmt.Println(err)
        panic(err)

    }
    if err := r.Body.Close(); err != nil {
        panic(err)
    }

// retrieve post data  and set it to params which is CodeLocatorParams type
    var params CodeLocatorParams
    if err := json.Unmarshal(data, &params ); err != nil {
        w.Header().Set("Content-Type", "application/json; charset=UTF-8")
        w.WriteHeader(422) // unprocessable entity
        if err := json.NewEncoder(w).Encode(err); err != nil {
            fmt.Println(err)
            panic(err)
        }
    }





    var result struct{
        Locator string `json:"locator"`
    }
// here actually comes the func that generates random code and return it as string, but for now, just set it static
    result.Locator = "DPEWX22"

    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    json.NewEncoder(w).Encode(result)


}

Upvotes: 0

Views: 174

Answers (1)

Thundercat
Thundercat

Reputation: 120941

There is an error parsing the incoming JSON. This error is written to the response as {"Value":"string","Type":{},"Offset":26,"Struct":"CodeLocatorParams","Field":"lenght"}. The handler continues to execute and writes the normal response {"locator":"DPEWX22"}.

Here's how what to fix:

  • After writing error response, return from the handler.
  • The input JSON has lenght as a string value. Either change the struct field from int to string or modify the input to pass an integer.

Upvotes: 1

Related Questions