Get a particular URL in Node JS other ways - javascript

I have a REST API of Reddit. I am trying to parse the JSON output to get the URL of the responses. When I try to send the request, I get multiple outputs, but I am not sure how to do it as it's a random response.
https
.get("https://www.reddit.com/r/cute/random.json", resp => {
let data = "";
resp.on("data", chunk => {
data += chunk;
});
const obj = JSON.parse(data);
resp.on("end", () => {
console.log(obj.url);
});
})
.on("error", err => {
console.log("Error: " + err.message);
});
This is the code I have got. I used the default Node's http library and I don't think it worked. I have never used any Node Libraries, so it will be helpful if you can suggest them too. And also let me know if what I have done is right.

I understand that http is a core library of Node JS, but I strongly suggest you to use something like node-fetch. Make sure you run the following command on your terminal (or cmd) where your package.json file exists:
$ npm install node-fetch
This will install the node-fetch library, which acts similarly to how the Web based fetch works.
const fetch = require("node-fetch");
const main = async () => {
const json = await fetch("https://www.reddit.com/r/cute/random.json").then(
res => res.json()
);
console.log(
json
.map(entry => entry.data.children.map(child => child.data.url))
.flat()
.filter(Boolean)
);
};
main();
The URLs that you are looking for, I could find in the data.children[0].data.url so I did a map there. I hope this is something that might help you.
I get multiple output for the same code, run multiple times, because the URL you have used is a Random Article Fetching URL. From their wiki:
/r/random takes you to a random subreddit. You can find a link to /r/random in the header above. Reddit gold members have access to /r/myrandom, which is right next to the random button. Myrandom takes you to any of your subscribed subreddits randomly. /r/randnsfw takes you to a random NSFW (over 18) subreddit.
The output for me is like this:
[ 'https://i.redd.it/pjom447yp8271.jpg' ] // First run
[ 'https://i.redd.it/h9b00p6y4g271.jpg' ] // Second run
[ 'https://v.redd.it/lcejh8z6zp271' ] // Third run
Since it has only one URL, I changed the code to get the first one:
const fetch = require("node-fetch");
const main = async () => {
const json = await fetch("https://www.reddit.com/r/cute/random.json").then(
res => res.json()
);
console.log(
json
.map(entry => entry.data.children.map(child => child.data.url))
.flat()
.filter(Boolean)[0]
);
};
main();
Now it gives me:
'https://i.redd.it/pjom447yp8271.jpg' // First run
'https://i.redd.it/h9b00p6y4g271.jpg' // Second run
'https://v.redd.it/lcejh8z6zp271' // Third run
'https://i.redd.it/b46rf6zben171.jpg' // Fourth run
Preview
I hope this helps you. Feel free to ask me if you need more help. Other alternatives include axios, but I am not sure if this can be used on backend.

Related

Fetch all of the Discord threads on a server (Discord.js)

I'm starting out in Discord.js and trying to make a bot that prints all of the thread data from the server to the console. For all threads on the server, I basically want it to print just the name of the thread, the member who created the thread, and the timestamp it was made.
Previously I was working on code for one that prints thread entries from the audit log, but because that data deletes after 45 days, I'm looking to make a more efficient strategy to print all threads that have ever been made since the beginning of the server (or at least this year).
I found this post on fetching all channel ids for the server, and that code works for me, but when I try to convert that code to find data on threads, I'm struggling to figure out how to do that.
Does anyone have any suggestions on how I could approach this?
EDIT 4:
The code is now working to print some thread data, but I can't print more than 100 entries. I found this post that might help with pulling that data, but I need to convert it to threads rather than messages to use that.
With my code to print using cached data, it only prints 5-10, but if I pull from the audit log, I'm able to print up to 100. I still don't think that's the method I want though because it will delete after 45 days and I'd like to at least pull all data one time, then from there I can use this command to just pull less data after the initial pull if I do it more frequently.
Here's my current code:
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
client.on('ready', () =>{
console.log(`${client.user.tag}` + ' is online!');
})
// should be more specific with message, (so it can be like "!audit")
client.on('messageCreate', async function (message) {
const fetchedLogs = await message.guild.fetchAuditLogs({
limit: 100,
type: 110, // THREAD_CREATE
action_type: 110 // THREAD_CREATE
});
//const fetchedChannels = await message.guild.channels.fetch();
// Checks which command was done; message.content gets the message that the user sent to trigger this:
if(message.content === "!test"){
// get the guild
const guild = client.guilds.cache.get("694998889358557297");
// filter all the channels
const threads = guild.channels.cache.sort((a, b) => a.createdAt - b.createdAt).filter(x => x.isThread());
// Title of the Thread
const threadTitle = threads.map(info => `${info.name}`);
// ID of the Thread Creator
const threadUser = threads.map(info => `${info.ownerId}`);
// Date the Thread was Created
const threadDate = threads.map(info => `${info.createdAt}`);
// ALL INFO, if you want an array just remove the ".join()"
const threadInfo = threads.map(info => `Name: ${info.name}\nCreator: ${info.ownerId}\nCreated at: ${info.createdAt}\n`).join("");
console.log(threadTitle);
//console.log(threadUser);
//console.log(threadDate);
//console.log(threadInfo);
}
else {
console.log ("target doesn't exist");
}
});
Threads are just channels that are parented to another channel, so you can fetch them all the same way as normal channels and then filter the result to only include threads.
const threads = channels.cache.filter(x => x.isThread());
This will result in the threads variable being an array of threads for the guild.
You can just filter through all the guild's channels and find the ones that are a thread.
// get the guild
const guild = client.guilds.cache.get("guild ID");
// filter all the channels
const threads = guild.channels.cache.filter(x => x.isThread());
Then, you can map the information that you need:
// if you want an array just remove the ".join()"
const threadInfo = threads.map(info => `Name: ${info.name}\nCreator: ${info.ownerId}\nCreated at: ${info.createdAt}\n`).join("");
constole.log(threadInfo);

How to write requests and fetch

I need help how to correctly write a GET and POST request in my server (index.js) and how to properly write the fetch in App.js.
I have read threads here on Stackoverflow and I have searched for information on how to write requests and fetches but I find it very difficult how to add the examples to my own code. I have tried different solutions for three weeks but getting nowhere it feels like. So, please help. I feel like this should not be that difficult, but for some reason it is. I have no one to ask for help other than here.
I'm using the URL http://localhost:8080/reviews
Is this how I write or do I have to add anything? (in Index.js)
app.get("/reviews", (request, response) => {
response.status(201).json
});
app.post('/reviews', async (request, response) => {
response.status(201).json
});
In App.js I want to create a fetch where I GET all the existing reviews that are written (none at the moment since the page isn't done yet) and I want to be able to POST new reviews. When I post a new review I want the page to load and update with the new and all the other written reviews.
I have something like this at the moment, but I don't know what the last parts should be?
const reviewsURL = "http://localhost:8080/reviews"
export const App = () => {
const [existingReviews, setExistingReviews] = useState([])
const [newReview, setNewReview] = useState('')
const fetchReviews = () => {
fetch(reviewsURL, {'
// WHAT ELSE TO WRITE HERE ???
useEffect(() => {
fetchReviews();
}, []);
const postReview = (event) => {
event.preventDefault();
fetch(reviewsURL, {
method: 'POST',
// WHAT DO I WRITE HERE ???
}
return (
<>
<NewReview
newReview={newReview}
setNewReview={setNewReview}
handlesubmit={postReview}
/>
{<AllReviews
allReviews={existingReviews}
/>}
</>
)
}
In express.js, response.status(201).json is not the way to return a JSON response. .json is a function, so you would pass it a JSON-ifiable object, response.status(201).json(resultsArray); or something like that.
A lot of people prefer to use a library for making requests, rather than using fetch. Axios is a common favourite, and lots of people find it much easier to use.
If you'd prefer to use fetch over an easier library, that's fine, fetch is still simple enough to get going with. Here's some documentation on how to use fetch
Of note: the fetch(url) function returns a promise, so you'll either .then the returned promise, or await it inside an async function. If you're expecting a JSON response, the patterns in the example code in the docs require an extra step to get the content:
const result = await fetch(url);
const data = await result.json();
That's for a GET request, but the docs also show how to get going with POST requests.

Command that takes info from FiveM

I would like to build a command , in Node.js with Visual Studio Code, which will take data from FiveM and will show in a message how many players are online and if there is a Queue !
I will post an image and I will show what i mean:
I am using a code that logs in console and the code is :
const Gamedig = require('gamedig');
Gamedig.query({
type: 'fivem',
host: 'fivem.example.com'
}).then((state) => {
console.log(state);
}).catch((error) => {
console.log("Server is offline");
});
I would like to ask if there is a way to set as command and display "image" view!
According to the gamedig documentation, the state param that is going in the callback function have not that much predefined properties. You can retrieve directly how many players are online by the players.length property, accessing it by state.players.length inside the callback function in the then() method. But there's too a raw property which seems to return all the info the server gives you back, so you can try to parse it and retrieve any other relevant info.
Use the FiveM package to get server info.
You can get the players like this:
const FiveM = require("fivem") // Import the npm package.
const srv = new FiveM.Server('IP:PORT') // Set the IP with port.
srv.getPlayers().then(data => console.log(data)) // Get & log the data!
or the whole server object:
srv.getServer().then(data => console.log(data)) // Get & log the data!
Enjoy.

Running query from inside Cloud Function using request parameters

I am having troubles running queries from Cloud Functions using the request parameters to build the query form HTTP calls. In the past, I have ran queries from cloud functions fine with no error. My problem arises when I try to run the query using parameters gotten from the request.
When I hardcode the location of the document in the function, it works fine but when I try to build a query, it returns status code of 200. I have also logged the the built query and it is logging out the right thing but no data is being returned. It only returns data when the document path is hardcoded. See code below.
Query looks like this
https://us-central1-<project-id>.cloudfunctions.net/getData/CollectionName/DocumentName
export const getData = functions.https.onRequest((request, response) => {
const params = request.url.split("/");
console.log("the params 0 "+params[0]);
console.log("the params 1 "+params[1]);
console.log("the params 2 "+params[2]);
//Build up the document path
const theQuery = "\'"+params[1]+"\/"+params[2]+"\'";
console.log("the query "+theQuery); <-- logs out right result in the form 'Collection/Document'
//Fetch the document
const promise = admin.firestore().doc("\'"+params[1]+"\/"+params[2]+"\'").get() <---- This doesnt work, building the query
//const promise = admin.firestore().doc('collectionName/DocID').get() <---- This hard coded and it works
promise.then(snapshot => {
const data = snapshot.data()
response.send(data)
}).catch(error => {
console.log(error)
response.status(500).send(error);
})
});
I tried using a different approach and giving the datafields a names as seen below
Query looks like this
https://us-central1-<project-id>.cloudfunctions.net/getData?CollectionName=CName&DocumentID=Dname
export const getData = functions.https.onRequest((request, response) => {
const collectName = request.query.CollectionName;
const DocId = request.query.DocumentName;
//Build up the document path
const theQuery = "'"+collectName+"\/"+collectName+"'";
console.log("the query "+theQuery); <---Logs out correct result
//Fetch the document
const promise = admin.firestore().doc(theQuery).get() <-- Building the query does not work
//const promise = admin.firestore().doc('collectionName/DocID').get() <---- This hard coded and it works
promise.then(snapshot => {
const data = snapshot.data()
response.send(data)
}).catch(error => {
console.log(error)
response.status(500).send(error);
})
});
In both cases, when the request is build from the URL, it does not return any data and it does not return any errors. And I am sure the documents I am trying to fetch exsist in the database. Am I missing anything ?
Try request.path. Then you can obtain the path components, e.g. request.path.split("/")[1]
The syntax for request.query is valid when using Express. This is referenced in some of the docs, but not made explicit that Express is required. It's confusing.
To properly handle the dynamic inputs, you may have more luck working with Express and creating routes and handlers. This Firebase page has links to some projects using it.
Walkthough set-up using Express on Firebase.

CF Connect to the cloud controller

I use the following lib to connect to the cloud controller
https://github.com/prosociallearnEU/cf-nodejs-client
const endpoint = "https://api.mycompany.com/";
const username = "myuser";
const password = "mypass";
const CloudController = new (require("cf-client")).CloudController(endpoint);
const UsersUAA = new (require("cf-client")).UsersUAA;
const Apps = new (require("cf-client")).Apps(endpoint);
CloudController.getInfo().then((result) => {
UsersUAA.setEndPoint(result.authorization_endpoint);
return UsersUAA.login(username, password);
}).then((result) => {
Apps.setToken(result);
return Apps.getApps();
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I try to run it against our API and its not working and Im not getting no error message in the console, what it can be ?
where does the space/org is handled here ? since when I connect from the cli it ask me to which space/org I want to connect...
Im able to login via the CLI, just from the code I cant, any idea what is missing here?
The issue it when I run it I dont get any error that can help to understand what is the root cause
I cloned the original git repository and modified some methods to support proxy. Please note that I modified just some methods to get the sample code working, but a complete refactor of the package is needed.
Basically what you have to do is to add a proxy parameter before calling the request method (this is done throughout the package, so several modifications are needed), for example this is for one of the methods in the Organization.js file:
getSummary (guid) {
const url = `${this.API_URL}/v2/organizations/${guid}/summary`;
const proxy = `${this.API_PROXY}`;
const options = {
method: "GET",
url: url,
proxy: proxy,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
You can find my changes in the git repository below:
https://github.com/adasilva70/cf-nodejs-client.git
I have also created a new sample below. This sample lists all organizations for a user, gets the first organization returned and lists its spaces. You can modify the code to provide a similar functionality that cf login provides (allow you to select an organization then a space).
const endpoint = "https://api.mycompany.com/";
const username = "youruser";
const password = "yourpassword";
const proxy = "http://proxy.mycompany.com:8080";
const CloudController = new (require("cf-nodejs-client")).CloudController(endpoint, proxy);
const UsersUAA = new (require("cf-nodejs-client")).UsersUAA;
const Apps = new (require("cf-nodejs-client")).Apps(endpoint, proxy);
const Orgs = new (require("cf-nodejs-client")).Organizations(endpoint, proxy);
CloudController.getInfo().then((result) => {
console.log(result);
UsersUAA.setEndPoint(result.authorization_endpoint, proxy);
return UsersUAA.login(username, password);
}).then((result) => {
//Apps.setToken(result);
//return Apps.getApps();
Orgs.setToken(result);
return Orgs.getOrganizations();
}).then((result) => {
console.log(result);
org_guid = result.resources[1].metadata.guid;
return Orgs.getSummary(org_guid);
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I have done just minor tests to make sure the sample works, so use carefully. Also, the changes will only work for a case where proxy is needed now.
The first thing that strikes me on the library's github site is the warning:
Note: This package is not ready for a production App yet.
It also seems that the project is not being maintained as there are a number of tickets ooened that are quite a few months old that don't have a response.
Anyway, to figure out why the library is not working and producing no error message, I would check out the library source code and add some console logging statements, probably starting with the HttpUtils. For example:
requestWithDefaults(options, function (error, response, body) {
console.log("requestWithDefaults error: ", error)
console.log("requestWithDefaults response: ", response)
console.log("requestWithDefaults body: ", body)
...
}
Alternatively, you could try debugging the code by adding breakpoints to the requestWithDefaults and other key places in the library, using the nodejs debugger.
You could also try debugging the network calls similar to this how to monitor the network on node.js similar to chrome/firefox developer tools?
To understand how to use the library, I would take a look into the tests folder and look for a test that is similar to your use case. There are a reasonable amount if tests that look useful in the test/lib/model/cloudcontroller folder.
As for the question about spaces, I have found an example where you can pass in a space guid to return apps for that space guid.
CloudFoundrySpaces.getSpaceApps(space_guid, filter).then( ... )
I'm assuming the call you are using App.getApps() will return Apps for all spaces/organizations.

Categories

Resources