I tried to come up with a good challenge to learn some Rx.js programming and I came up with this chain of operations below. As well as a bit of code that works and does these things.

  1. Take github username
  2. Create folder based on username (/repos-${user})
  3. Get all repos for username (https://api.github.com/users/${user}/repos)
  4. Get the hash of the repo data
  5. Create file where name is hash and content is repo

I'm looking for insights and optimizations, shortcuts, etc, to make this better.

Here's the code.

import { join } from 'path'
import axios from 'axios'
import Rx from 'rx'
import Promise from 'bluebird'
import crypto from 'crypto'
import fs from 'fs-extra'
import Debug from 'debug'

let debug = Debug('github-repos')


let {
  outputJsonAsync } = fs

function getRepos (user) {
  let theUrl = `https://api.github.com/users/${user}/repos`
  return axios.get(theUrl)
  .then(result => {
    debug(`got results back for ${user}`)
    return result.data

function getHash (json) {
  let text = JSON.stringify(json)
  return crypto.createHash('md5').update(text).digest('hex')

function createDir (user) {
  return ensureDirAsync(join(__dirname, `/repos-${user}`))

function createFile (user, hash, data) {
  let file = join(__dirname, `/repos-${user}/${hash}.json`)
  return outputJsonAsync(file, data).then(x => file)

let ghUser$ = Rx.Observable.from(['reggi', 'jackofseattle', 'nolanlawson'])

let ensureUser$ = ghUser$
  .do((u) => debug(`Creating directory for: ${u}`))
  .flatMap(u => createDir(u))

let getRepos$ = ghUser$
  .do((u) => debug(`fetching user repos for: ${u}`))
  .flatMap(u => getRepos(u))

let repos$ = getRepos$
  .flatMap(repos => repos.map(repo => ({hash: getHash(repo), repo})))  // create hash for each

let fileWriter$ = repos$
  .map(repo => ({user: repo.repo.owner.login, hash: repo.hash, repo: repo.repo}))
  .flatMap(({user, hash, repo}) => {
    return createFile(user, hash, repo)
  .do((file) => debug(`wrote a new repo to json ${file}`))

let reposSubscription = fileWriter$.subscribe(
  function (x) {
  function (err) {
     console.log('Error: %s', err)
  function (e) {

1 Answer 1


The code looks really easy to read to me, so I think you did well, really!

  • Consider using const instead of let.
  • You use #debug() in some places and console#log() in other places. If you can use another parallel instance of #debug() to remove the #log(), you will have some more control over logging.

Maybe you could extract the side-effects calls in #do() to not be part of the main stream, and create a separate stream that you can activate and deactivate. This will be overkill for your code, but in a bigger app, it would probably be nice.

Well done anyhow!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.