question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use Ruby's Native JSON conversion rather than outputting a JSON string

See original GitHub issue

i.e instead of:

  body = " { \"a\": 123 }"

Do:

  require 'json'
  body = { a: 123 }.to_json

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:2
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
dimitropouloscommented, Jul 21, 2022

note: re 1. above, https://github.com/Kong/httpsnippet/pull/285 made the OpenSSL::SSL::VERIFY_NONE line configurable.

0reactions
sandstromcommented, Jul 27, 2022

@dimitropoulos Both works, but JSON.generate is better (more obvious, less risk of conflict with other ruby gems).

Easier to understand that this is the json gem being used (it’s used in both cases, but with to_json that’s not very obvious), and there is no risk of some other code having patched/shadowed the to_json method (unlikely, but can happen).

However, after looking at the source for Python (fairly similar to Ruby), I realize that it’s some work.

I’ve tried to put something together here, that would go onto these lines:

https://github.com/Kong/httpsnippet/blob/911ab772bc2b1cd271024ea1efeab14614d28de0/src/targets/ruby/native/client.ts#L77-L79

switch (postData.mimeType) {
  // Special handling for JSON only, since that's the most common one.
  // Could add e.g. 'multipart/form-data' too, see Python snippet, but it's more work.
  case 'application/json':
    if (postData.jsonObj) {
      push(`payload = ${literalRepresentation(postData.jsonObj)}`);
      push('request.body = JSON.generate(payload)');
    }
    break;

  // fallback
  default: {
    let payload = JSON.stringify(postData.text);
    
    if (payload) {
      push(`request.body = ${payload}`);
    }
  }
}

Would need to add this as a helper (similar to the Python snippet):

function concatValues(
  concatType: 'array' | 'object',
  values: any,
  pretty: boolean,
  indentation: string,
  indentLevel: number,
) {
  const currentIndent = indentation.repeat(indentLevel);
  const closingBraceIndent = indentation.repeat(indentLevel - 1);
  const join = pretty ? `,\n${currentIndent}` : ', ';
  const openingBrace = concatType === 'object' ? '{' : '[';
  const closingBrace = concatType === 'object' ? '}' : ']';

  if (pretty) {
    return `${openingBrace}\n${currentIndent}${values.join(
      join,
    )}\n${closingBraceIndent}${closingBrace}`;
  }

  if (concatType === 'object' && values.length > 0) {
    return `${openingBrace} ${values.join(join)} ${closingBrace}`;
  }

  return `${openingBrace}${values.join(join)}${closingBrace}`;
}

/**
 * Create a valid Ruby string of a literal value according to its type.
 *
 * @param {*} value Any JavaScript literal
 * @return {string}
 */
export const literalRepresentation = (
  value: any,
  indentLevel?: number,
): any => {
  let indent = '  '; // 2 spaces is default ruby indent
  indentLevel = indentLevel === undefined ? 1 : indentLevel + 1;

  switch (Object.prototype.toString.call(value)) {
    case '[object Number]':
      return value;

    case '[object Array]': {
      let pretty = false;
      const valuesRepresentation: any = (value as any[]).map(v => {
        // Switch to prettify if the value is a dictionary with multiple keys
        if (Object.prototype.toString.call(v) === '[object Object]') {
          pretty = Object.keys(v).length > 1;
        }
        return literalRepresentation(v, indentLevel);
      });
      return concatValues('array', valuesRepresentation, pretty, indent, indentLevel);
    }

    case '[object Object]': {
      const keyValuePairs = [];
      for (const key in value) {
        keyValuePairs.push(`"${key}": ${literalRepresentation(value[key], indentLevel)}`);
      }
      return concatValues(
        'object',
        keyValuePairs,
        keyValuePairs.length > 1,
        indent,
        indentLevel,
      );
    }

    case '[object Boolean]':
      return value ? 'true' : 'false';

    default:
      if (value === null || value === undefined) {
        return 'nil';
      }
      return `"${value.toString().replace(/"/g, '\\"')}"`;
  }
};

See these two files for background, and the necessary require calls etc. to load the helper.

https://github.com/Kong/httpsnippet/blob/911ab772bc2b1cd271024ea1efeab14614d28de0/src/targets/python/requests/client.ts

https://github.com/Kong/httpsnippet/blob/911ab772bc2b1cd271024ea1efeab14614d28de0/src/targets/python/helpers.ts

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to convert a ruby hash object to JSON? - Stack Overflow
I can understand ActiveRecord is a Rails object, but Hash is not native to Rails, it's a pure Ruby object. So in Rails...
Read more >
Module: JSON (Ruby 2.6.3)
JSON.generate only allows objects or arrays to be converted to JSON syntax. to_json , however, accepts many Ruby classes even though it acts...
Read more >
Handling JSON Data - Real World OCaml
Our first task is to parse the JSON into a more structured OCaml type so that we can use static typing more effectively....
Read more >
flori/json: JSON implementation for Ruby - GitHub
It's recommended to use the extension variant of JSON, because it's faster than the pure ruby variant. If you cannot build it on...
Read more >
JSON.stringify() - JavaScript - MDN Web Docs
The JSON.stringify() method converts a JavaScript value to a JSON string, optionally replacing values if a replacer function is specified or ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found