Using POST in terminal for MongoDB returns ObjectParameterError - mongodb

I just started learning about MongoDB and Node.js and was confused about this error. I created this app through the next.js template.
The error I am getting is
error - ObjectParameterError: Parameter "obj" to Document() must be an object, got {"title":"X","content":"XXX"}
Where I tried inserting the data through this line on my terminal
curl -X POST -d '{"title":"X","content":"XXX"}' -H 'Content-Type: application/json' localhost:3000/api/blogs/articles
Here is the code...
import { connect, model, models, Schema } from "mongoose"
const connectionString = 'mongodb+srv://user1:2bhEHe22GdtH1idX#cluster0.t27tcax.mongodb.net/blogs'
export default async function handler(req, res) {
await connect(connectionString);
console.log("req.method: ", req.method)
if (req.method === 'GET') {
const docs = await Article.find()
res.status(200).json(docs)
} else if (req.method === 'POST') {
console.log(req.body)
res.status(200).json(req.body)
// const doc = await Article.create(req.body)
// res.status(201).json(doc)
} else {
res.setHeader('Allow', ['GET', 'POST'])
res.status(405).end(`Method ${req.method} Not Allowed`)
}
}
const articleSchema = new Schema({
title: String,
content: String,
});
console.log("Mongoose Models", models)
const Article = models?.article || model('article', articleSchema);
I've took a look at a similar post (Saving data into MongoDb returns an ObjectParameterError) and it seems that all I've already implemented their fixes. Thank you for any help you can give.

Related

Google Storage REST get with axios

I want to get a list of images in a bucket using REST and axios.
ref: https://cloud.google.com/storage/docs/listing-objects#list-objects-json
The documentation gives this curl request
curl -X GET -H "Authorization: Bearer OAUTH2_TOKEN" \
"https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o"
reqConfig: this is a token I use in my REST firestore queries to authenticate the user. I'm using that same token for here. I'm guessing it's the problem but not sure how to fix it.
My result is consistently 404 for a bucket path that I know exists, using the URL from their docs. I should be getting a json list of the files in the bucket.
Error: Request failed with status code 404
Where am I going wrong?
export async function getCompanyStorage(context, apikey, companyId) {
const url = `https://storage.googleapis.com/storage/v1/b/uploads/${companyId}/o?key=${apikey}`;
const cookies = nookies.get(context);
const reqConfig = {
headers: new Headers({
Authorization: "Bearer " + cookies.token,
"Content-Type": "application/json",
}),
};
const result = axios
.get(url, { headers: { Authorization: `Bearer ${reqConfig}` } })
.then((res) => {
return res.data;
})
.catch((error) => {
console.error("error using axios", error);
});
}
Edit: a path to a bucket in the firebase console looks like this
gs://projectname.appspot.com/uploads/WhmDZyQdLVk7n0qR7aTg
I suggest reviewing the documentation you linked to. In particular:
OAUTH2_TOKEN is the access token you generated in Step 1.
BUCKET_NAME is the name of the bucket whose objects you want to list. For example, my-bucket.
You can use a prefix=PREFIX query string parameter to limit results to
objects that have the specified prefix.
Your URL does not contain the name of the bucket as required by the URL pattern. Use the unique name of the bucket where you see "BUCKET_NAME". It looks like, given your example, that it would be "projectname.appspot.com". BUCKET_NAME is not the path of the object within that bucket. If you want to list files under the "uploads" prefix, then you would use the prefix query string parameter to specify that, as documented in the last line of the quoted text.
You can use this function to create Get request with axios for Google Cloud Storage
export const UploadVideo = async (form_data, file, signedurl, asset_uuid) => {
let resultState = { state: '', data: {} };
console.log(signedurl)
/*
const xhr = new XMLHttpRequest();
xhr.open("PUT", signedurl);
xhr.setRequestHeader('Content-Type', "application/octet-stream");
xhr.send(file);
*/
let config = {
headers: {
'Content-Type': 'application/octet-stream',
},
};
await axios.get(signedurl, file, config).then(function (response) {
resultState.state = 'success';
}).catch(function (error) {
resultState.state = 'error';
resultState.data.message = error.message;
window.toastr.error(error.message);
console.log(error)
})
return resultState;
}

how to store user session into request object in expressjs

I am newbie in expressjs and read a very popular MERN project now.After an user(buyer) log into site and place an order which will be added into Mongodb tagged with the user(buyer),the backend code like below:
const addOrderItems = asyncHandler(async (req, res) => {
const {
orderItems,
shippingAddress,
paymentMethod,
itemsPrice,
taxPrice,
shippingPrice,
totalPrice,
} = req.body
if (orderItems && orderItems.length === 0) {
res.status(400)
throw new Error('No order items')
return
} else {
const order = new Order({
orderItems,
user: req.user._id,
shippingAddress,
paymentMethod,
itemsPrice,
taxPrice,
shippingPrice,
totalPrice,
})
const createdOrder = await order.save()
res.status(201).json(createdOrder)
}
})
Link:https://github.com/bradtraversy/proshop_mern/blob/master/backend/controllers/orderController.js
But where the req.user._id comes from?I check the whole project,some popular backend session or storage tools like express-session and cookie-sessiondid not installed and used.
It's comes from passport package. It will log user with JWT and populate the user property of the req object.

rest-hapi standalone endpoint not returning handler results

Forgive me if it's a silly question, but the last time I coded in javascript was almost 20 years ago... I'm re-learning javascript these weeks and I'm not sure I got it all.
I'm using hapi with rest-hapi and want to add some standalone endpoints, basically translating the backend portion of this Autodesk tutorial form express.
I'm using the basic rest-hapi example main script, and tried to add a route with the following code:
//api/forge.js
module.exports = function(server, mongoose, logger) {
const Axios = require('axios')
const querystring = require('querystring')
const Boom = require('boom')
const FORGE_CLIENT_ID = process.env.FORGE_CLIENT_ID
const FORGE_CLIENT_SECRET = process.env.FORGE_CLIENT_SECRET
const AUTH_URL = 'https://developer.api.autodesk.com/authentication/v1/authenticate'
const oauthPublicHandler = async(request, h) => {
const Log = logger.bind('User Token')
try {
const response = await Axios({
method: 'POST',
url: AUTH_URL,
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: 'client_credentials',
scope: 'viewables:read'
})
})
Log.note('Forge access token retrieved: ' + response.data.access_token)
return h.response(response.data).code(200)
} catch(err) {
if (!err.isBoom){
Log.error(err)
throw Boom.badImplementation(err)
} else {
throw err
}
}
}
server.route({
method: 'GET',
path: '/api/forge/oauth/public',
options: {
handler: oauthPublicHandler,
tags: [ 'api' ],
plugins: {
'hapi-swagger': {}
}
}
})
}
The code works and I can display the access_token in nodejs console, but swagger doesn't get the response:
At first I thought that an async function cannot be used as handler, but my hapi version is 17.4.0, and it supports async handlers.
What am I doing wrong?
It turns out it was an easy fix: I just needed to specify the Hapi server hostname in my main script!
The problem was with CORS, since Hapi used my machine name instead of localhost. Using
let server = Hapi.Server({
port: 8080,
host: 'localhost'
})
solved my problem.

Image returned from REST API always displays broken

I am building a content management system for an art portfolio app, with React. The client will POST to the API which uses Mongoose to insert into a MongoDB. The API then queries the DB for the newly inserted image, and returns it to the client.
Here's my code to connect to MongoDB using Mongoose:
mongoose.connect('mongodb://localhost/test').then(() =>
console.log('connected to db')).catch(err => console.log(err))
mongoose.Promise = global.Promise
const db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
const Schema = mongoose.Schema;
const ImgSchema = new Schema({
img: { data: Buffer, contentType: String }
})
const Img = mongoose.model('Img', ImgSchema)
I am using multer and fs to handle the image file. My POST endpoint looks like this:
router.post('/', upload.single('image'), (req, res) => {
if (!req.file) {
res.send('no file')
} else {
const imgItem = new Img()
imgItem.img.data = fs.readFileSync(req.file.path)
imgItem.contentType = 'image/png'
imgItem
.save()
.then(data =>
Img.findById(data, (err, findImg) => {
console.log(findImg.img)
fs.writeFileSync('api/uploads/image.png', findImg.img.data)
res.sendFile(__dirname + '/uploads/image.png')
}))
}
})
I can see in the file structure that writeFileSync is writing the image to the disk. res.sendFile grabs it and sends it down to the client.
Client side code looks like this:
handleSubmit = e => {
e.preventDefault()
const img = new FormData()
img.append('image', this.state.file, this.state.file.name)
axios
.post('http://localhost:8000/api/gallery', img, {
onUploadProgress: progressEvent => {
console.log(progressEvent.loaded / progressEvent.total)
}
})
.then(res => {
console.log('responsed')
console.log(res)
const returnedFile = new File([res.data], 'image.png', { type: 'image/png' })
const reader = new FileReader()
reader.onloadend = () => {
this.setState({ returnedFile, returned: reader.result })
}
reader.readAsDataURL(returnedFile)
})
.catch(err => console.log(err))
}
This does successfully place both the returned file and the img data url on state. However, in my application, the image always displays broken.
Here's some screenshots:
How to fix this?
Avoid sending back base64 encoded images (multiple images + large files + large encoded strings = very slow performance). I'd highly recommend creating a microservice that only handles image uploads and any other image related get/post/put/delete requests. Separate it from your main application.
For example:
I use multer to create an image buffer
Then use sharp or fs to save the image (depending upon file type)
Then I send the filepath to my controller to be saved to my DB
Then, the front-end does a GET request when it tries to access: http://localhost:4000/uploads/timestamp-randomstring-originalname.fileext
In simple terms, my microservice acts like a CDN solely for images.
For example, a user sends a post request to http://localhost:4000/api/avatar/create with some FormData:
It first passes through some Express middlewares:
libs/middlewares.js
...
app.use(cors({credentials: true, origin: "http://localhost:3000" })) // allows receiving of cookies from front-end
app.use(morgan(`tiny`)); // logging framework
app.use(multer({
limits: {
fileSize: 10240000,
files: 1,
fields: 1
},
fileFilter: (req, file, next) => {
if (!/\.(jpe?g|png|gif|bmp)$/i.test(file.originalname)) {
req.err = `That file extension is not accepted!`
next(null, false)
}
next(null, true);
}
}).single(`file`))
app.use(bodyParser.json()); // parses header requests (req.body)
app.use(bodyParser.urlencoded({ limit: `10mb`, extended: true })); // allows objects and arrays to be URL-encoded
...etc
Then, hits the avatars route:
routes/avatars.js
app.post(`/api/avatar/create`, requireAuth, saveImage, create);
It then passes through some user authentication, then goes through my saveImage middleware:
services/saveImage.js
const createRandomString = require('../shared/helpers');
const fs = require("fs");
const sharp = require("sharp");
const randomString = createRandomString();
if (req.err || !req.file) {
return res.status(500).json({ err: req.err || `Unable to locate the requested file to be saved` })
next();
}
const filename = `${Date.now()}-${randomString}-${req.file.originalname}`;
const filepath = `uploads/${filename}`;
const setFilePath = () => { req.file.path = filepath; return next();}
(/\.(gif|bmp)$/i.test(req.file.originalname))
? fs.writeFile(filepath, req.file.buffer, (err) => {
if (err) {
return res.status(500).json({ err: `There was a problem saving the image.`});
next();
}
setFilePath();
})
: sharp(req.file.buffer).resize(256, 256).max().withoutEnlargement().toFile(filepath).then(() => setFilePath())
If the file is saved, it then sends a req.file.path to my create controller. This gets saved to my DB as a file path and as an image path (the avatarFilePath or /uploads/imagefile.ext is saved for removal purposes and the avatarURL or [http://localhost:4000]/uploads/imagefile.ext is saved and used for the front-end GET request):
controllers/avatars.js (I'm using Postgres, but you can substitute for Mongo)
create: async (req, res, done) => {
try {
const avatarurl = `${apiURL}/${req.file.path}`;
await db.result("INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ($1, $2, $3)", [req.session.id, avatarurl, req.file.path]);
res.status(201).json({ avatarurl });
} catch (err) { return res.status(500).json({ err: err.toString() }); done();
}
Then when the front-end tries to access the uploads folder via <img src={avatarURL} alt="image" /> or <img src="[http://localhost:4000]/uploads/imagefile.ext" alt="image" />, it gets served up by the microservice:
libs/server.js
const express = require("express");
const path = app.get("path");
const PORT = 4000;
//============================================================//
// EXPRESS SERVE AVATAR IMAGES
//============================================================//
app.use(`/uploads`, express.static(`uploads`));
//============================================================//
/* CREATE EXPRESS SERVER */
//============================================================//
app.listen(PORT);
What it looks when logging requests:
19:17:54 INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ('08861626-b6d0-11e8-9047-672b670fe126', 'http://localhost:4000/uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png', 'uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png')
POST /api/avatar/create 201 109 - 61.614 ms
GET /uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png 200 3027 - 3.877 ms
What the user sees upon successful GET request:

Finding total contributions of a user from GitHub API

I am trying to extract the below info for any user from GitHub.
Is there a way/API exposed in GitHub REST API where we can get this information directly?
Answers for 2019, Use GitHub API V4.
First go to GitHub to apply for a token: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line. step 7, scopes select only read:user
cUrl
curl -H "Authorization: bearer token" -X POST -d '{"query":"query {\n user(login: \"MeiK2333\") {\n name\n contributionsCollection {\n contributionCalendar {\n colors\n totalContributions\n weeks {\n contributionDays {\n color\n contributionCount\n date\n weekday\n }\n firstDay\n }\n }\n }\n }\n}"}' https://api.github.com/graphql
JavaScript
async function getContributions(token, username) {
const headers = {
'Authorization': `bearer ${token}`,
}
const body = {
"query": `query {
user(login: "${username}") {
name
contributionsCollection {
contributionCalendar {
colors
totalContributions
weeks {
contributionDays {
color
contributionCount
date
weekday
}
firstDay
}
}
}
}
}`
}
const response = await fetch('https://api.github.com/graphql', { method: 'POST', body: JSON.stringify(body), headers: headers })
const data = await response.json()
return data
}
const data = await getContributions('token', 'MeiK2333')
console.log(data)
Yes, You can do this easily with the new graphql API
Check out the explorer: https://developer.github.com/v4/explorer/
There you can see the contributions collection which is an edge of the user. You can get all of the information necessary to rebuild the calendar.
I've included a full example, and the explorer documentation can guide you even further.
Specifically to answer your question, the query.user.contributionsCollection.contributionsCalendar.totalContributions
is what you are looking for
Go ahead and copy/paste the following into the explorer and you will see my contribution history for the last year
query {
user(login: "qhenkart") {
email
createdAt
contributionsCollection(from: "2019-09-28T23:05:23Z", to: "2020-09-28T23:05:23Z") {
contributionCalendar {
totalContributions
weeks {
contributionDays {
weekday
date
contributionCount
color
}
}
months {
name
year
firstDay
totalWeeks
}
}
}
}
}
To load the svg with all contributions you can use this code in your html page
<img src="https://ghchart.rshah.org/username" alt="Name Your Github chart">
To customize color you can just do that
<img src="https://ghchart.rshah.org/HEXCOLORCODE/username" alt="Name Your Github chart">
HEXCOLORCODE = 17A2B8
You can use the github events api for that:
Example (node.js)
const got = require('got')
async function getEvents(username) {
const events = []
let page = 1
do {
const url = `https://api.github.com/users/${username}/events?page=${page}`
var { body } = await got(url, {
json: true
})
page++
events.push(...body)
} while(!body.length)
return events
}
(async () => {
const events = await getEvents('handtrix')
console.log('Overall Events', events.length)
console.log('PullRequests', events.filter(event => event.type === 'PullRequestEvent').length)
console.log('Forks', events.filter(event => event.type === 'ForkEvent').length)
console.log('Issues', events.filter(event => event.type === 'IssuesEvent').length)
console.log('Reviews', events.filter(event => event.type === 'PullRequestReviewEvent').length)
})()
Example (javascript)
async function getEvents(username) {
const events = []
let page = 1
do {
const url = `https://api.github.com/users/${username}/events?page=${page}`
var body = await fetch(url).then(res => res.json())
page++
events.push(...body)
} while(!body.length)
return events
}
(async () => {
const events = await getEvents('handtrix')
console.log('Overall Events', events.length)
console.log('PullRequests', events.filter(event => event.type === 'PullRequestEvent').length)
console.log('Forks', events.filter(event => event.type === 'ForkEvent').length)
console.log('Issues', events.filter(event => event.type === 'IssuesEvent').length)
console.log('Reviews', events.filter(event => event.type === 'PullRequestReviewEvent').length)
})()
Documentation
https://developer.github.com/v3/activity/events/
https://developer.github.com/v3/activity/events/types/
https://www.npmjs.com/package/got
You can get the svg calendar from https://github.com/users/<USER>/contributions with to URL parameter like :
https://github.com/users/bertrandmartel/contributions?to=2016-12-31
You can use a basic xml parser to sum all the contributions from the svg.
An example with curl & xmlstarlet for year 2016:
curl -s "https://github.com/users/bertrandmartel/contributions?to=2016-12-31" | \
xmlstarlet sel -t -v "sum(//svg/g/g/rect/#data-count)"
I believe you can see count of contributions in a timeframe as well as other individual contributor analytics within Code Climate’s Velocity git analytics, which you may request access to here: https://go.codeclimate.com/velocity-free-for-teams
You could use this function to extract the contributions from the last year (client):
function getContributions(){
const svgGraph = document.getElementsByClassName('js-calendar-graph')[0];
const daysRects = svgGraph.getElementsByClassName('day');
const days = [];
for (let d of daysRects){
days.push({
date: d.getAttribute('data-date'),
count: d.getAttribute('data-count')
});
}
return days;
}
I've also written a small node module which can 'extract' the contributions
#simonwep/github-contributions
Maybe this will help you (even I'm 4 years to late)
If you would prefer a npm package, you can try this.
https://github.com/SammyRobensParadise/github-contributions-counter#readme
You can get all time contributions or contributions by each year.