DEV Community

Craft Delivery
Craft Delivery

Posted on

Expo.js apps using a localhost backend over ngrok

The issue arises when creating React Native apps using Expo.js where you wish to have a local backend instead of a live url. Ngrok is used by many to accomplish this, however, if you are using a free account it can take some repeated effort to keep everything working

Free Ngrok urls are only available for 90 minutes, after which you need to restart it and get a fresh url

We can automate the process to make it as painless as possible

All files mentioned should be created in the project root beside package.json

Ensure axios and expo-constants are installed: expo add axios expo-constants

We will assume your local api is running on port 3333

First create a script called local in package.json:

  "scripts": {
    "start": "expo start",
    "local": "node ngrokhandler.js && EXPO_NGROK=1 expo start",
    ...
  }
Enter fullscreen mode Exit fullscreen mode

Pass EXPO_NGROK=1 to expo start that way app.config.js can choose to load ngrok or just ingore it

Once you've added all the pieces, start the app locally using yarn run local

create a file ngrokhandler.js

Note: if this is your only tunnel, then the local ngrok server is on port 4040, if you have more than one this number increments, so note it when you start ngrok. If you see a number greater than 4040, you may have ngrok running elsewhere

const fs = require('fs')
const axios = require('axios')

// ngrok starts at port 4040
// subsequent tunnels are numbered 4040 + n
axios.get('http://127.0.0.1:4040/api/tunnels')
.then(resp => {
  const httpsTunnel = resp.data.tunnels.find(t => t.proto==='https')
  const url = httpsTunnel.public_url
  fs.writeFileSync('./NGROK_URL', url)
})
.catch(e => {
  console.log('START NGROK in another window: ngrok http 3333')
  // exit err code so && in package json does not execute the expo start command
  process.exit(2)
})
Enter fullscreen mode Exit fullscreen mode

This writes the current https tunnel url to a text file called NGROK_URL

Create or modify app.config.js:

const fs = require('fs')

// on production ngrokUrl will be null
// you don't need to have the file NGROK_URL
// in production

let ngrokUrl = null
if (process.env.EXPO_NGROK === '1') {
  ngrokUrl = fs.readFileSync('./NGROK_URL', { encoding: 'utf8'})
}

export default ({ config }) => {
  return {
    ...config,
    extra: {
      ...config.extra,
      ngrokUrl,
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This brings in your app.json via the config param and adds the ngrok url to the extra object. Put anything else you want to add in extra

You can then access this via expo-constants. You probably don't want to use an ngrok url in production so we can turn it off by applying the __DEV__ variable expo provides:

Example: api.js:

import Constants from 'expo-constants'
const { ngrokUrl } = Constants.manifest.extra

const isLocal = ngrokUrl && __DEV__

const productionUrl = 'https://example.com'

const baseUrl = isLocal ? ngrokUrl : productionUrl

// now we can export an object of api endpoints
export default {
  login: `${baseUrl}/login`,
  etc: ...
}
Enter fullscreen mode Exit fullscreen mode

Get your api running on port 3333.

Open another terminal and enter ngrok http 3333

Now you can run the app using yarn run local and the local url will be automatically added to the app. You have 90 minutes before you'll need to break the expo app and ngrok and re-run the commands (ctrl-c, up and enter in each terminal window)

Top comments (0)