Last active
April 17, 2025 11:21
-
-
Save ornicar/a097406810939cf7be1df8ea30e94f3e to your computer and use it in GitHub Desktop.
Read a ND-JSON stream from the browser or from nodejs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* FOR THE BROWSER | |
Utility function to read a ND-JSON HTTP stream. | |
`processLine` is a function taking a JSON object. It will be called with each element of the stream. | |
`response` is the result of a `fetch` request. | |
See usage example in the next file. | |
*/ | |
const readStream = processLine => response => { | |
const stream = response.body.getReader(); | |
const matcher = /\r?\n/; | |
const decoder = new TextDecoder(); | |
let buf = ''; | |
const loop = () => | |
stream.read().then(({ done, value }) => { | |
if (done) { | |
if (buf.length > 0) processLine(JSON.parse(buf)); | |
} else { | |
const chunk = decoder.decode(value, { | |
stream: true | |
}); | |
buf += chunk; | |
const parts = buf.split(matcher); | |
buf = parts.pop(); | |
for (const i of parts.filter(p => p)) processLine(JSON.parse(i)); | |
return loop(); | |
} | |
}); | |
return loop(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* FOR NODEJS | |
Utility function to read a ND-JSON HTTP stream. | |
`processLine` is a function taking a JSON object. It will be called with each element of the stream. | |
`response` is the result of a `fetch` request. | |
See usage example in the next file. | |
*/ | |
const readStream = processLine => response => { | |
const matcher = /\r?\n/; | |
const decoder = new TextDecoder(); | |
let buf = ''; | |
return new Promise((resolve, fail) => { | |
response.body.on('data', v => { | |
const chunk = decoder.decode(v, { stream: true }); | |
buf += chunk; | |
const parts = buf.split(matcher); | |
buf = parts.pop(); | |
for (const i of parts.filter(p => p)) processLine(JSON.parse(i)); | |
}); | |
response.body.on('end', () => { | |
if (buf.length > 0) processLine(JSON.parse(buf)); | |
resolve(); | |
}); | |
response.body.on('error', fail); | |
}); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* From browser or nodejs alike */ | |
const stream = fetch('https://lichess.org/api/tv/feed'); | |
// or any other ND-JSON endpoint such as: | |
// const stream = fetch('https://lichess.org/api/games/user/neio',{headers:{Accept:'application/x-ndjson'}}); | |
const onMessage = obj => console.log(obj); | |
const onComplete = () => console.log('The stream has completed'); | |
stream | |
.then(readStream(onMessage)) | |
.then(onComplete); |
@konpa Sorry but no... I started again using Ionic and there I had success
@rodolphonetto Ok, then I'll keep looking for a solution :) Thanks for your answer!
Just as information, in case it could help someone with the same problem, I managed to make it work with react native (only tested on iOS for now) using acostalima/react-native-polyfill-globals and the web-streams-polyfill, inexorabletash/text-encoding and react-native-community/fetch dependencies.
Hi @konpa Is it possible to make a little exemple of how did you done? It can be helpfull for begginers
Thanks!
Sure.
Install dependancies
npm install react-native-polyfill-globals text-encoding react-native-fetch-api web-streams-polyfill
MyComponentScreen.native.tsx
(polyfill are not needed/working for web)
import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding';
import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream';
import { polyfill as polyfillFetch } from 'react-native-polyfill-globals/src/fetch';
polyfillEncoding();
polyfillReadableStream();
polyfillFetch();
[...]
const readStream = (processLine) => (response) => {
// same as browser-ndjson-stream-reader.js above
[...]
}
const stream = fetch(`https://lichess.org/api/board/game/stream/${gameId}`, {
reactNative: { textStreaming: true },
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: 'application/x-ndjson',
},
});
const onMessage = (obj) => console.log(obj);
const onComplete = () => console.log('The stream has completed');
stream
.then(readStream(onMessage))
.then(onComplete);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@rodolphonetto I'm trying to do the same, did you find any way to do this with react native ?