I know that rendering should be done by the themes.
That is not exactly correct. Theme functions are generally defined from modules, and themes can override them, or implement a theme function that is specific for a purpose.
If you are creating the output for a page, the code for generating it should be in a module. That is because it's a module that can implement hook_menu(), which is the hook that defines the menu callback used for pages.
That is what is done from Drupal core code with node_view(), which is the page callback for node/%node, and node/%node/view. The page callback is defined from the Node module, not from a theme; themes can eventually alter the output of node_view()
through the node.tpl.php template file used from node_view()
to render the node page.
As for outputting the result, there are two methods:
- Returning a string containing the HTML output
- Returning an array with a specific structure (it is called render array) that can be used from drupal_render()
As example of a page callback that returns a string, see aggregator_view(); as example of page callback that returns a render array, see node_view().