Why isn't my json data formatted nicely in the browser? - express

I'm learning Express and I just built a JSON API with CRUD operations to the database
It's working but I'm wondering why my JSON data is formatted like that on the browser
[{"_id":"5f253d105f194d4c8074227d","firstName":"John","lastName":"Doe","age":38,"__v":0},{"_id":"5f253d3a5f194d4c8074227e","firstName":"Jane","lastName":"Doe","age":33,"__v":0}]
I want it to be formatted like
[
{
"_id":"5f253d105f194d4c8074227d",
"firstName":"John",
"lastName":"Doe",
"age":38,
"__v":0},
{
"_id":"5f253d3a5f194d4c8074227e",
"firstName":"Jane",
"lastName":"Doe",
"age":33,
"__v":0}
]
This is the function I use to get the users
router.get("/", async (req, res) => {
try {
const getUsers = await Users.find();
res.json(getUsers);
} catch (err) {
res.json({ message: err.message });
}
});

You only need a JSON formatter for your browser, you can use a formatter like JSON Formatter for Chrome or for JSONView Firefox. Or you can test your API responses with any API client (like Insomnia, Postman, Postwoman...) instead of testing it on your browser
Edit:
If you want (for any reason) to send pre-formatted/human readable JSON responses, you can do so by using JSON.stringify, example:
app.get("/formatted", (req, res) => {
const formattedResponse = JSON.stringify(data, null, 2)
res.type('json').send(formattedResponse)
});

Related

Fetching Wikipedia article via Node.js returns a corrupted response

I have some very basic code for getting a Wikipedia page:
router.get("/article-info/:name", async (req, res) => {
// get contents of a wikipedia article
const { data } = await axios.get(
`https://en.wikipedia.org/w/api.php?action=parse&page=${req.params.name}&format=json`
);
console.log(data);
});
But it returns unicode nonsense like:
\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003�1%\f�\nnJ<HT齦齁-齖齘X �$�\u0004\u0001\u001a\u00003E�#�\u0004\u0002)w�7齁b88齛牺Z\u0007Y\u001e~>-C齍\u0018\u000f\u0006齘齣|wnw:齫�3齂E�?z淉A颻\\x齃7齴Sdt?_齓1\u000f齓\u0016(M�$](\u000e�,\u00050齠齚稞�!�?u\u001cl�'i\u0012R&�8梌n齣�=jwa\u001f齙�?r\t�<(�&Ur\u001e�7�8�\u0005\u0005J�\u0014�\"gY齰Fx#m齱�\f�$-nr\"齓}�>o齙\u0007齳�,齫xS<o_\r齂U�-9M�\"]=o]�?�K齩&i�\n�\u0003�8Jn齎�7齂d\u0018齊\u0011齙Nh\u0011`\u001a�\u0006g\u001ac\u0018>-\u000b�\"齉\u0017)U�+hRaL\f�\u000b齣齗�\u001bz&齨V\r\u001a齝�-�>v}\u001f鼺�4\u001b}5\u001b3�\u0010齍\f�;齝4qn:�\u000e&R齳�<k齀�,XM鼺\rL\u001du辇齆~[\\+391N^\u0016\u000bvr決B7C\u0019q�0=齮Xu5,齙.齊Gn2(\u000bg鼼]\u001a�\u0011$7l鼸q鼲Q=|�-�\u001bc齰?A齙l齛D�7�7\u001c\u000f泯\r'Jn齣齩\u001f<o<齲;T[fw齷4/MXR齎\u0017�D�\b�'#�\u0013鼳!N�\"K7|9K�4{^dA齋齯9[F齖�6\\�\u0003齲W4\u0003鼳齕齘齍~Ku]�\u001d2\f�\u0017\u001ag鼵]齢k�\u000b齵齳鼶+:{齠\u0013�'�4p�7�\u0000[$齡4齛fO�\u0002zfA6齢\u000ec{�/齗齇F齕z�\b� 齏:�,s齏齣k淉/<;/齰]�\u001fg*u?HuQ>Cs鼺�5齏z齝v^\r-\u0010\u000f齊\u000f齭�\f齇;\nf鼼齇齵w.齍齲�\u0011u�*]妖-�(齧齵\u0019�=齅齸\u0019�>�/><\u000f齕jP#Z齛Z齡3t�5mpi0鼴睚x\bl�\u001d
Going to the URL gives me the result I expect in the browser.
https://en.wikipedia.org/w/api.php?action=parse&page=The_Beatles&format=json

Access request body in ServerMiddleware in NUXT

Im building a simple interface to SeaTable. For security reasons, I'm not storing the DB and user keys in the code but instead set up a very lightweight API in NUXT using Server Middle wear. All is working as expected except for my login API endpoint.. I need to capture req.data but it's not available. All examples I have seen add body-phraser and Express. I don't wanna use express as I want to keep this as light as possible.
import fetch from 'node-fetch';
export default {
path: 'api/auth/login',
handler: async (req, res) => {
let requestOptions = {
method: "POST",
headers: {
"username": usr,
"password": psw
}
}
const url = 'https://MY_URL.com/api2/auth-token/'
const request = await fetch(url, requestOptions)
const data = await request.json()
res.end( JSON.stringify(data) )
}
}
I suppose since this call does not contain any keys i could just make the call on the front end capture the user token and send it to the backend to be stored. Id prefer not to expose even the URL to my seatable instance.

Vue, Axios, making a get request to YouTube search API return 404

Not sure what I am doing wrong. I am trying to make a get request to YouTube API for a keyword. The query string now is returning 404 I a have added referring urls and have current api key.
My method where I am making call with axios.The location logs out fine.
async getYouTubeVideoId(location) {
console.log({ location })
try {
const response = await axios.get(
`https://www.googleapis.com/youtube/v3/search?key="mykeyinquotes"&type=video&part=snippet&maxResults=5&q=${location}`
)
console.log(response.data)
} catch (error) {
console.log({ error })
}
},
Here is where I am calling method
async created() {
this.getLocationData()
await this.getWikiData(this.pickedLocation.name)
await this.getYouTubeVideoId(this.pickedLocation.name)
this.asyncDataStatus_fetched()
}
API key should not be in quotes.

Importing API Routes

How should I rewrite this as a function?
I'm building a tool using Next.JS & using their api endpoint to interact with MongoDB.
The NextJS website says:
Note: You should not use fetch() to call an API route in your application. Instead, directly import the API route and call its function yourself. You may need to slightly refactor your code for this approach.
Fetching from an external API is fine!
How should I refactor my code to adjust to this approach?
import handler from '../../middleware/common_middleware';
handler.get(async (req, res) => {
try {
let query = req.query;
let queryName = Object.values(query)[0];
let doc = await req.db.collection("Volunteers").find({"_id": queryName}).toArray();
res.status(201).json(doc);
}
catch {
res.status(400).send("The profile doesn't exist.");
}
});
export default handler;
Looking at NextJS doc here:
https://nextjs.org/docs/api-routes/introduction
https://github.com/vercel/next.js/blob/canary/examples/api-routes-rest/pages/api/users.js
you probably should have a structure like this:
export default async (req, res) => {
try {
let query = req.query;
let queryName = Object.values(query)[0];
// modify with the module to make query to db
let doc = await req.db.collection("Volunteers").find({"_id": queryName}).toArray();
res.statusCode = 201;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({status:'success', data: doc});
}
catch {
res.statusCode = 400
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({status: 'error', data: 'The profile doesn't exist.' }))
}
}
Didn't try it but hope it gives an idea.

How do I design my Node.js API so that I can also consume it from the server side?

I have an API that returns some JSON from mongodb:
// In router.js
var api = require('api')
app.get('/lists', api.lists);
// In api.js
var db = require('db')
exports.lists = function(req, res) {
db.lists.find({}, function(err, lists) {
res.send(lists);
});
};
Is there a way to design the API so that I could also consume it from within my Node.js app? I'm trying to avoid having to duplicate any of the database code outside the API. I basically have a controller that can render the data server-side:
// In controller.js
var api = require('api')
exports.page = function(req, res) {
res.send(api.lists()); // This won't work
};
I found a hacky solution which was to pass a callback function to the api.lists(), but I have a feeling this is the "wrong" way to achieve this:
// In api.js
exports.lists = function(req, res, callback) {
db.lists.find({}, function(err, lists) {
if(callback){
callback(lists);
} else {
res.send(lists);
}
});
};
Any ideas?
I think the problem is that in your current code you are coupling your API to the response object. You can decouple them with something like this:
In router.js instead of using api.lists as the callback, define a function that will call api.lists with a callback that is wired to the response object. In this case api.list DOES NOT need to know about the response object but the function that we are creating does.
// In router.js
var api = require('api');
app.get('/lists', function(req, res) {
api.lists(function(err, lists) {
if(err) {
res.send('error page');
return;
}
res.send(lists);
});
});
In api.js we remove the reference to the response object. Now it will just call whatever callback it received with the appropriate data (err + lists). It's up to the callback to do whatever it pleases with the result.
// In api.js
var db = require('db')
exports.lists = function(callback) {
db.lists.find({}, function(err, lists) {
callback(err, lists);
});
};