├── .gitignore ├── package.json ├── server.js ├── LICENSE ├── yarn.lock ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-network-proxy", 3 | "version": "1.0.1", 4 | "description": "Network proxy for react-native applications", 5 | "main": "index.js", 6 | "author": "Kureev Alexey ", 7 | "license": "MIT", 8 | "bin": { 9 | "react-native-network-proxy": "./server.js" 10 | }, 11 | "dependencies": { 12 | "prettyjson": "^1.2.1", 13 | "ws": "^3.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const WebSocket = require('ws'); 4 | const prettyjson = require('prettyjson'); 5 | 6 | const wss = new WebSocket.Server({ port: 6969 }); 7 | 8 | wss.on('connection', ws => 9 | ws.on('message', (message) => { 10 | try { 11 | const parsed = JSON.parse(message); 12 | parsed.requestHeaders = JSON.parse(parsed.requestHeaders); 13 | parsed.responseHeaders = JSON.parse(parsed.responseHeaders); 14 | console.log('\n\n────────────────────REQUEST START────────────────────\n\n'); 15 | console.log(prettyjson.render(parsed)); 16 | console.log('\n\n────────────────────REQUEST END────────────────────\n\n'); 17 | } catch(e) {} 18 | }) 19 | ); 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Alexey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | colors@^1.1.2: 6 | version "1.1.2" 7 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 8 | 9 | minimist@^1.2.0: 10 | version "1.2.0" 11 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 12 | 13 | prettyjson@^1.2.1: 14 | version "1.2.1" 15 | resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" 16 | dependencies: 17 | colors "^1.1.2" 18 | minimist "^1.2.0" 19 | 20 | safe-buffer@~5.0.1: 21 | version "5.0.1" 22 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" 23 | 24 | ultron@~1.1.0: 25 | version "1.1.0" 26 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864" 27 | 28 | ws@^3.0.0: 29 | version "3.0.0" 30 | resolved "https://registry.yarnpkg.com/ws/-/ws-3.0.0.tgz#98ddb00056c8390cb751e7788788497f99103b6c" 31 | dependencies: 32 | safe-buffer "~5.0.1" 33 | ultron "~1.1.0" 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 🛠 Network debug tool for react-native 2 | 3 | Ever struggled with debugging network requests in React Native? Prefer console tools over GUI solutions (like [reactotron](https://github.com/infinitered/reactotron))? 4 | 5 | ![react-native-network-proxy](http://i.imgur.com/kNtLzUr.jpg) 6 | 7 | ## Getting started 8 | 9 | - Install `react-native-network-proxy` by running 10 | 11 | ```bash 12 | $ yarn add react-native-network-proxy 13 | ``` 14 | or 15 | ```bash 16 | $ npm i react-native-network-proxy --save 17 | ``` 18 | 19 | - Add `react-native-network-proxy` to your react-native application: 20 | 21 | ```js 22 | import { start as startNetworkDebugging } from 'react-native-network-proxy'; 23 | 24 | startNetworkDebugging({ 25 | host: 'localhost', 26 | port: 6969, 27 | }); 28 | 29 | // or just startNetworkDebugging(); 30 | ``` 31 | 32 | - Start `react-native-network-proxy` server: 33 | 34 | ```bash 35 | $ yarn react-native-network-proxy 36 | ``` 37 | or 38 | ```bash 39 | $ npm run react-native-network-proxy 40 | ``` 41 | 42 | - That's it! Run your app and make your `fetch`/`XMLHttpRequest`! The request should appear in the console where the server is running 43 | 44 | ## Help 45 | 46 | You can always reach me on [twitter (@kureevalexey)](https://twitter.com/@kureevalexey) 47 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import XHRInterceptor from 'react-native/Libraries/Network/XHRInterceptor'; 2 | 3 | function convertURLStringToHash(data) { 4 | const formattedData = {}; 5 | const dataArr = data.split('&'); 6 | dataArr.forEach(d => { 7 | const item = d.split('='); 8 | const key = item[0]; 9 | const value = item[1]; 10 | formattedData[key] = value; 11 | }); 12 | 13 | return formattedData; 14 | } 15 | 16 | export function start(config = { 17 | host: 'localhost', 18 | port: 6969, 19 | }) { 20 | const ws = new WebSocket(`ws://${config.host}:${config.port}`); 21 | 22 | const defaultMessage = { 23 | requestHeaders: {}, 24 | responseHeaders: {}, 25 | }; 26 | 27 | let message = defaultMessage; 28 | 29 | XHRInterceptor.setOpenCallback((protocol, url) => { 30 | message.protocol = protocol; 31 | message.url = url; 32 | }); 33 | 34 | XHRInterceptor.setSendCallback((d) => { 35 | try { 36 | message.data = convertURLStringToHash(d); 37 | } catch (e) { 38 | if (d) { 39 | message.data = d; 40 | } 41 | } 42 | }); 43 | XHRInterceptor.setRequestHeaderCallback((header, value) => { 44 | message.requestHeaders[header] = value; 45 | }); 46 | XHRInterceptor.setHeaderReceivedCallback((header, value) => { 47 | message.responseHeaders[header] = value; 48 | }); 49 | XHRInterceptor.setResponseCallback((status, _, payload) => { 50 | message.response = JSON.parse(payload); 51 | message.requestHeaders = JSON.stringify(message.requestHeaders); 52 | message.responseHeaders = JSON.stringify(message.responseHeaders); 53 | ws.send(JSON.stringify(message)); 54 | message = defaultMessage; 55 | }); 56 | 57 | XHRInterceptor.enableInterception(); 58 | } 59 | 60 | export function stop() { 61 | XHRInterceptor.disableInterception(); 62 | } 63 | --------------------------------------------------------------------------------