How to stream asynchronous string from server - deno

I'm trying to stream the html response in Deno but can't quite figure it out.
Doing it from a Service Worker on the front end looks like this:
async function streamResponse(html: {start: (s: string) => Promise<void>}) {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller : ReadableStreamDefaultController<any>) {
const send = (item: string) => controller.enqueue(encoder.encode(item))
await html.start(send)
controller.close()
}
})
return new Response(stream, { headers: { "content-type": "text/html; charset=utf-8" }})
}
When I do something similar to that in Deno (req.respond({body: stream, headers})) it says that the body can't be of the type ReadableStream. I know there is some way to do this. I just can't figure it out. What am I missing? I looked in multiple places trying to understand how it is done but I haven't found any good example yet.

Figured it out. I need to use Deno.Buffer as the writer and then bring in BufReader to wrap the writer.
import { BufReader } from "https://deno.land/std#0.79.0/io/bufio.ts"
import { ServerRequest } from "https://deno.land/std#0.79.0/http/server.ts"
import { HTML } from "./html.ts"
var headers = new Headers({
"Content-Type": "text/html"
})
const encoder = new TextEncoder()
export async function toHTML(req: ServerRequest, html: Promise<HTML>) {
var buffer = new Deno.Buffer()
var body = new BufReader(buffer)
var h = await html
req.respond({body, headers})
await h.start((item: string) => buffer.write(encoder.encode(item)))
}

Related

Telegram bot won't respond even doe webhook is set

The code for the bot is currently hosted on a Cloudflare worker, and there are no errors being reported from that end. Additionally, upon investigation of the Botfather side, everything seems to be functioning normally as well. However, despite attempting various solutions such as changing bots, tokens, and chat groups, the issue remains.
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const { pathname } = new URL(request.url)
if (pathname === '/') {
return new Response('Hello! This is a Telegram bot. Send me a message.')
}
const { text } = await request.json()
if (text.startsWith('/start')) {
return new Response('Welcome to the bot! Use the /help command to see available options.')
} else if (text.startsWith('/help')) {
return new Response('Available commands:\n/scrape - scrapes videos from the specified website and sends them to the Telegram chat.\n/<example> - scrapes posts from the specified website and sends them to the Telegram chat.')
} else if (text.startsWith('/scrape')) {
const videoUrl = await scrapeVideoUrl('<example url>')
const message = `Here's the latest video: ${videoUrl}`
await sendMessageToChatId(message)
return new Response('OK')
} else if (text.startsWith('/<example>')) {
const post = await scrapePost('<example url>')
const message = `Here's the latest post: ${post.title}\n${post.url}`
await sendMessageToChatId(message)
return new Response('OK')
} else {
return new Response('Invalid command. Use the /help command to see available options.')
}
}
async function scrapeVideoUrl(url) {
const response = await fetch(url)
const html = await response.text()
const cheerio = require('cheerio')
const $ = cheerio.load(html)
const videoUrl = $('div.media > a').attr('href')
return videoUrl
}
async function scrapePost(url) {
const response = await fetch(url)
const html = await response.text()
const cheerio = require('cheerio')
const $ = cheerio.load(html)
const post = {
title: $('div.content h1').text(),
url: url
}
return post
}
async function sendMessageToChatId(message) {
const telegramApiUrl = "https://api.telegram.org/bot<token>/sendMessage";
const chatId = "<id>";
const response = await fetch(telegramApiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
chat_id: chatId,
text: message
})
})
}
There is zero response on the telegram side, even doe on web side everything seems to be fine.

How to resolve error fetching product from Shopify API

I am trying to fetch products from shopify API but don't understand why it's throwing an an error set in my catch statement. The error says
error - utils/fetchShop.js (28:10) # productData
Error: Products not fetched
26 | return data;
27 | } catch (error) {
> 28 | throw new Error('Products not fetched');
| ^
29 | }
30 | }
Can you help me figure out what I am doing wrong here. So basically I am
Creating a function called productData that will accept a query.
productData it will make a POST request to the Shopify Storefront GraphQL API using the set headers and return the json response.
productData function will return the data to the getAllProducts function which will set it equal to the allProducts variable.
Here is my code:
const domain = process.env.SHOPIFY_STOREFRONT_DOMAIN;
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;
async function productData(query) {
const URL = `https://${domain}/api/2022-04/graphql.json`;
const options = {
endpoint: URL,
method: 'POST',
headers: {
'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
query
}),
};
try {
const data = await fetch(URL, options).then((response) => {
return response.json();
});
return data;
} catch (error) {
throw new Error('Products not fetched');
}
}
export async function getAllProducts() {
const query = `{
products(first: 250) {
edges {
node {
handle
id
}
}
}
}`;
const response = await productData(query);
const slugs = response.data.products.edges ?
response.data.products.edges :
[];
return slugs;
}
So I had this exact problem. It seems to be something to do with the URL variable being all caps.
If you change:
const URL = `https://${domain}/api/2022-10/graphql.json`;
endpoint: URL
To:
const _url = `https://${domain}/api/2022-10/graphql.json`;
endpoint: _url
That should fix the problem. It worked for me.
Be sure to also change the variable in your fetch too to reflect the changes.
EDIT: As this variable is immutable I have added the underscore to note this.

Post request to normal route, not using API middleware

Below my pages directory i have a few routes (for example "/product/details").
I'm using getServerSideProps() to have the page render server side.
How can i send a POST request containing data in the body to this page directly?
The idea would be that i can do something like this:
export async function getServerSideProps(postData) {
return {
props: {postData.body},
}
}
I've tried console logging "postData". I can see that the post request headers are being sent, but the request body is missing.
Thanks
Edit:
I'm doing the posting using Postman, and i'm sending a raw body of type JSON containing a single key:value. But as i said, the page doesn't seem to receive the posted data.
Here is a code snippet for how i'm sending a post request to a route using puppeteer:
const page = await puppeteerConnection.newPage();
await page.setRequestInterception(true);
await page.once('request', (request) => {
let data = {
'method': 'POST',
'postData': JSON.stringify(jsonData),
'headers': {
...request.headers(),
'Content-Type': 'application/json'
},
};
request.continue(data);
page.setRequestInterception(false);
});
await page.goto('pathToNextJSRoute');
getServerSideProps() accepts a context parameter (which you've named postData in your example) and one of the keys in that object (req) contains the request body you're looking for. It arrives as a readable stream of byte data, though, so you'll need to convert it first:
const streamToString = async (stream) => {
if (stream) {
const chunks = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
return Buffer.concat(chunks).toString("utf-8");
}
return null;
};
export async function getServerSideProps(context) {
let data = null;
if (context.req.method === "POST") {
const body = await streamToString(context.req);
data = JSON.parse(body);
}
console.log(data);
return {
props: { data },
};
}

Flutter: HTTP get request body is empty

I'm playing a bit with Flutter and try to perform a http get request. Though I'm always getting an empty body in the response.
For example with the following code :
import 'package:http/http.dart' as http;
[...]
http.Client client = new http.Client();
client
.get("https://www.googleapis.com/books/v1/volumes?q=$text")
.then((http.Response response) {
print(response.statusCode);
print(response.body);
setState(() {
_isLoading = false;
});
});
I get the following result :
200
{
Do you have any ideas ?
Thanks by advance !
EDIT
It appears that the problem only happens on iOS devices. It works as expected on Android.
Can you try this below code. The code is untested.
import 'dart:io';
import 'dart:convert';
main() async {
try {
var client = new HttpClient();
String text = "example";
var uri = Uri.parse("https://www.googleapis.com/books/v1/volumes?q=$text");
var request = await client.getUrl(uri);
var response = await request.close();
var responseBody = await response.transform(UTF8.decoder).join();
print(responseBody);
} catch (exception) {
print(exception);
}
}
Probably you forget the headers , for example :
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest',
},
Try debugPrint() instead of print(). It will print all body to console
https://flutter.io/debugging/#print-and-debugprint-with-flutter-logs

Http post,with credentials.What I'm doing wrong?

1.I can't setup a proper request, with useCredentials.Can anyone tell me what's wrong with the code?
import { Injectable } from '#angular/core';
import { Http, Response,Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs/Observable';
#Injectable ()
export class StructureRequestService {
result: Object;
constructor (private http: Http) {
2.use XHR object - I think the problem is here.
let _build = (<any> http)._backend._browserXHR.build;
(<any> http)._backend._browserXHR.build = () => {
let _xhr = _build();
_xhr.withCredentials = true;
return _xhr;
};
}
private myUrl = 'http://manny.herokuapp.com/audit/get/structure';
//create an http request
sendRequest() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({
headers: headers
// , withCredentials: true
});
return this.http.post(this.myUrl,options)
.map((res: Response) => res.json())
.subscribe(res => {this.result = res;});
}
}
You are missing the post body parameter in your post request. It must be a string
return this.http.post(this.myUrl, body, options)
Body
Despite the content type being specified as JSON, the POST body must actually be a string. Hence, we explicitly encode the JSON hero content before passing it in as the body argument.
ref: https://angular.io/docs/ts/latest/guide/server-communication.html

Resources