How can I retrieve channel data in json format? I've played around with a few implementations but I still don't feel like either is right. 

I first came across building the JSON itself. This would be in a file at "craft/templates/entries.json".

[
  {% for entry in craft.entries.section('news').find() %}
    {
      "title": "{{ entry.title | e('js') }}",
      "body": "{{ entry.body | e('js') }}"
    } {% if not loop.last %},{% endif %}
  {% endfor %}
]


This worked but I didn't feel right about writing my own JSON so I came up with this approach instead.

{% set results = [] %}
{% for entry in craft.entries.section('news').find() %}
{%
  set results = results | merge([{
    'title': entry.title,
    'body': entry.body
  }])
%}
{% endfor %}
{{ results | json_encode() | raw }}


This works, the JSON will definitely end up valid and as a bonus it'll be condensed but it's not very reusable and when I add fields I need to adjust it.

What approach should I take to make a reliable way to query data from Craft and return json?
I just threw together a add-on that will provide a Twig filter called prune to allow you to more easily do what you're asking here.

https://github.com/mattstauffer/craftcms-prune

With prune you can now just do the following:

{{ craft.entries.section('news').find() | prune(['title', 'body']) | json_encode() | raw }}


Just pass in an array of the fields you want to pluck out. It's pretty new and could use some love, but it'll get the basics done for sure.