It's my first time using Next Js, Mongo DB and Postman. I am building an app and when sending the information I get a 500 error in postman.
In VSC all is ok and the console does not have any errors
Can you guide me with some ideas to fix it?
I hope that the information is sent correctly and that it gives me a 201 code. As in the screenshot of the tutorial
Link to tutorial:https://www.youtube.com/watch?v=Z-hACIsjv4E&t=3115s
I'am using mongoose to...
import mongoose from "mongoose";
const MONGO_URL = process.env.MONGO_URL;
console.log(process.env.MONGO_URL);
if (!MONGO_URL) {
throw new Error(
"Please define the MONGO_URL environment variable inside .env.local"
);
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(MONGO_URL, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
import dbConnect from "../../../util/mongo";
import Product from "../../../models/Product";
export default async function handler(req, res) {
const { method } = req;
dbConnect();
if (method === "GET") {
try {
} catch (err) {}
}
if (method === "POST") {
try {
const product = await Product.create(req.body);
req.status(201).json(product);
} catch (err) {
res.status(500).json(err);
}
}
}
import mongoose from "mongoose";
const OrderSchema = new mongoose.Schema(
{
customer: {
type: String,
required: true,
maxlength: 60,
},
address: {
type: String,
required: true,
maxlength: 200,
},
total: {
type: Number,
required: true,
},
status: {
type: Number,
default: 0,
},
method: {
type: Number,
required: true,
},
},
{ timestamps: true }
);
export default mongoose.models.Order || mongoose.model("Order", OrderSchema);
Related
just wanna have my custom credential provider which authenticate the entered username and password with Firebase Authentication on sign in page
pages/api/auth/[...nextauth].ts
import NextAuth from "next-auth"
import { getDatabase } from "firebase/database"
import { DB } from "../../../constants/firebase"
import { FirebaseAdapter } from "#next-auth/firebase-adapter"
import * as firestoreFunctions from "firebase/firestore"
import CredentialsProvider from "next-auth/providers/credentials"
export default NextAuth({
session: {
strategy: "database",
},
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
username: {
label: "Username",
type: "text",
placeholder: "somebody#gmail.com",
},
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const database = getDatabase()
console.log(database)
const user = {
id: 1,
usename: "j",
password: "123456789",
}
if (
credentials?.username === user.usename &&
credentials.password === "123456789"
) {
return user
}
return null
},
}),
],
adapter: FirebaseAdapter({
db: DB,
...firestoreFunctions,
}),
// pages: {
// signIn: "/auth/signin",
// signOut: "/auth/signout",
// error: "/auth/error", // Error code passed in query string as ?error=
// verifyRequest: "/auth/verify-request", // (used for check email message)
// newUser: "/auth/new-user", // New users will be directed here on first sign in (leave the property out if not of interest)
// },
callbacks: {
async jwt({ token, user }) {
if (user) {
token.email = user.email
}
return token
},
async session({ session, token, user }) {
if (token) {
session.user!.email = token.email
}
return session
},
redirect({ url, baseUrl }) {
if (url.startsWith(baseUrl)) return url
else if (url.startsWith("/"))
return new URL(url, baseUrl).toString()
return baseUrl
},
},
})
firebase.ts
import { initializeApp, getApp, getApps } from "firebase/app"
import { getAnalytics } from "firebase/analytics"
import { getFirestore } from "#firebase/firestore"
import { getStorage } from "#firebase/storage"
import getFirebaseObject from "./firebaseConfig"
const app = !getApps.length ? initializeApp(getFirebaseObject()) : getApp()
const DB = getFirestore(app)
const storages = getStorage()
const analytics = getAnalytics(app)
export { app, DB, analytics, storages }
as you see
const user = {
id: 1,
usename: "j",
password: "123456789",
}
in fact except of these static data wanna search and get right user info from the Firebase
I know there are a some other way of doing this but I like working with next-auth for last change wanna make sure there's a spot of light in this was ;)
i found this public repository where the author does something similar to what you want to achieve, which is create a custom token with your database credentials.
May be this repository can help you. It has a few errors, but it gave me a general idea about what to do, as I had a similar case.
try {
if (user !== null) {
await customTokenSignIn(user.id, user.email);
(await getUser(user.id)) ??
(await createUser(toReqUser(user, account)));
const data = await getUser(user.id);
setResUser(user, data as ResUser);
return true;
}
return false;
} catch (e) {
console.error(e);
return false;
}
const customTokenSignIn = async (id: string, email: string) => {
const hash = toHash(id);
const customToken = await adminAuth.createCustomToken(hash);
await auth.signInWithCustomToken(customToken).then((res) => {
res.user?.updateEmail(email);
});
await adminAuth.setCustomUserClaims(hash, { sid: id });
await createUserToken({ id: id, firebaseUid: hash });
};
The error happens at if cart[1]
The cart[1] is underlined and I can't deploy the code to Vercel.
Thought it was a stripe problem but I thoroughly checked stripes API and this code make as much sense as I can think of.
here's is the full file. its a .ts extension
import { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2020-03-02",
});
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
try {
const cartItems = req.body;
const line_items = validateCartItems(cartItems);
const subscriptionInCart = isSubscriptionInCart(cartItems);
const params: Stripe.Checkout.SessionCreateParams = {
mode: subscriptionInCart ? "subscription" : "payment",
payment_method_types: ["card"],
billing_address_collection: "auto",
shipping_address_collection: {
allowed_countries: ["US", "CA"],
},
line_items,
success_url: `${req.headers.origin}/result?session_id=. {CHECKOUT_SESSION_ID}`,
cancel_url: `${req.headers.origin}/use-shopping-cart`,
};
const checkoutSession: Stripe.Checkout.Session =
await stripe.checkout.sessions.create(params);
res.status(200).json(checkoutSession);
} catch (err: any) {
res.status(500).json({ statusCode: 500, message: err.message });
}
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
}
const validateCartItems = (cartDetails: any) => {
const validatedItems = [];
for (const sku in cartDetails) {
const product = cartDetails[sku];
const item = {
price: product.sku,
quantity: product.quantity,
};
validatedItems.push(item);
}
return validatedItems;
};
const isSubscriptionInCart = (cartDetails: any) => {
let subscriptionFound = false;
for (const cartItem of Object.entries(cartDetails)) {
if (cartItem[1].recurring) {
subscriptionFound = true;
}
}
return subscriptionFound;
};
As #juliomalves mentioned, your cartDetails is correctly identifying a type error.
You need to specify a type for cartDetails so that cartItem[1].recurring is expected to be defined in a way that matches with your use of it.
Something like const isSubscriptionInCart = (cartDetails: Array<{recurring: boolean}>) => { ...} or better yet defining your own type CartItem and using Array<CartItem>
Code under test
// imports
const router = express.Router()
// This is what needs to be mocked
const client = new AwesomeGraphQLClient({
endpoint: process.env.GRAPHCMS_URL || '',
fetch,
fetchOptions: {
headers: {
authorization: `Bearer ${process.env.GRAPHCMS_TOKEN}`
}
}
})
interface LoginRequest {
email: string
password: string
}
router.post(
'/login',
async (req: Request<{}, {}, LoginRequest>, res: Response) => {
try {
const JWT_SECRET = getEnvironment('JWT_SECRET')
const { email, password } = req.body
if (!email || !password) {
res.status(400).json({
message: 'auth.provide.credentials',
full: 'You should provide an email and password'
})
return
}
if (!JWT_SECRET) {
res.status(500).json({
message: 'auth.secret.not.found',
full: 'Secret not found'
})
// TODO error logging
return
}
const { appUsers } = await client.request<
GetUserByEmailResponse,
GetUserByEmailVariables
>(getUserByEmailQuery, {
email
})
if (appUsers.length === 0) {
res.status(404).json({
message: 'auth.wrong.credentials',
full: 'You provided wrong credentials'
})
return
}
const user = appUsers[0]
const result: boolean = await bcrypt.compare(password, user.password)
if (result) {
var token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET)
res.status(200).json({
token
})
return
}
res.status(200).json({
message: 'auth.wrong.credentials',
full: 'You provided wrong credentials in the end'
})
} catch (e) {
console.log('E', e)
const error: ErrorObject = handleError(e)
res.status(error.code).json(error)
}
}
)
Tests for code above
import request from 'supertest'
import app from '../../../app'
import { mocked } from 'ts-jest/utils'
import { compare } from 'bcrypt'
import { AwesomeGraphQLClient } from 'awesome-graphql-client'
const mockRequestFn = jest.fn().mockReturnValue({
appUsers: [
{
id: 'tests'
}
]
})
jest.mock('awesome-graphql-client', () => ({
AwesomeGraphQLClient: jest.fn().mockImplementation(() => ({
request: mockRequestFn
}))
}))
I am trying to mock a method on a non default exported class from Awesome GraphQL. I also want to spy on this method, so I created a separate jest.fn() with a return value. The problem is that request is not a function: TypeError: client.request is not a function.
How can I mock and spy on the method of a mocked non default exported class?
SOLUTION
Managed to find a workaround. Make the method a function that returns the called mockRequest. This way you can spy on AwesomeGraphQLClient.request with mockRequest.toHaveBeenCalledTimes(x).
let mockRequest = jest.fn().mockReturnValue({
appUsers: [
{
id: 'tests'
}
]
})
jest.mock('awesome-graphql-client', () => {
return {
AwesomeGraphQLClient: jest.fn().mockImplementation(() => {
return {
request: () => mockRequest()
}
})
}
})
Background
fastify
json schema
ajv
Problem
when i add the setErrorHandler to my project/index.js,it doesnt work.
require('module-alias/register')
const Fastify = require('fastify')
const PORT = process.env.PORT || 3000
const sequelize = require('./orm')
const swagger = require('./config').swagger
const localize = require('ajv-i18n')
const app = Fastify({
logger: {
prettyPrint: true
},
ajv: {
customOptions: {allErrors: true, jsonPointers: true },
plugins: [
require('ajv-errors')
]
}
})
app.register(require('fastify-sensible'))
app.register(require('fastify-swagger'), swagger)
app.register(require('./plugin/systemlogs'))
app.register(require('./plugin/authenticate')).then(()=>{
const routes = require('./routes')
routes(app).forEach((route, index) => {
app.route(route)
})
})
app.setErrorHandler((error,request,reply)=>{
if (error.validation) {
localize.ru(error.validation)
reply.status(400).send(error.validation)
return
}
reply.send(error)
})
const start = async () => {
try {
await sequelize.sync({})
app.log.info('database sync correctly')
await app.listen(PORT, '0.0.0.0')
app.swagger()
} catch (err) {
app.log.error(err)
process.exit(1)
}
}
start()
Question
i want to turn the error to chinese with ajv i18n ,what should i do? i do in this way but it doesnt work
how can i use ajv-i18n in fastify ?
where should i add the setErrorHandler?
there are another way to deal with this issue.
thanks:
L2jLiga https://github.com/L2jLiga
Manuel Spigolon
url:
https://github.com/fastify/help/issues/317
this is another way:
const fastify = require('fastify')
const localize = require('ajv-i18n')
const app = fastify({
ajv: {
customOptions: { allErrors: true, jsonPointers: true },
plugins: [
require('ajv-errors')
]
},
schemaErrorFormatter: (errors, dataVar) => {
localize.ru(errors);
const myErrorMessage = errors.map(error => error.message.trim()).join(', ');
return new Error(myErrorMessage)
}
})
app.get('/', {
schema: {
querystring: {
type: "object",
properties: { a: { type: "string", nullable: false } },
required: ["a"],
},
},
}, async function (req, res) {})
app.listen(3000)
and example of response:
{
"statusCode": 400,
"error": "Bad Request",
"message": "должно иметь обязательное поле a"
}
Here a working snippet to play with; I think your issue is on the routes' schemas.
const Fastify = require('fastify')
const localize = require('ajv-i18n')
const app = Fastify({
logger: true,
ajv: {
customOptions: { allErrors: true, jsonPointers: true }
}
})
app.post('/', {
schema: {
body: {
type: 'object',
properties: {
foo: { type: 'integer' }
}
}
}
}, () => {})
app.setErrorHandler((error, request, reply) => {
if (error.validation) {
localize.ru(error.validation)
reply.status(400).send(error.validation)
return
}
request.log.error({ err: error })
reply.send(error)
})
app.inject({
method: 'POST',
url: '/',
payload: {
foo: 'string'
}
}, (_, res) => {
console.log(res.json())
})
That will print out:
[
{
keyword: 'type',
dataPath: '/foo',
schemaPath: '#/properties/foo/type',
params: { type: 'integer' },
message: 'должно быть integer'
}
]
My goal is to process a test payment using Stripe in a React JS web app. When I enter the test card information, I receive a 404 Error with the following message: "POST /api/payment_intents 404 (Not Found)". Why isn't the "axios.post("/api/payment_intents", method able to locate my payment intents?
[https://github.com/ChicagoJoe1991/saas-template][1]
import Stripe from "stripe";
const stripe = new Stripe(process.env.REACT_APP_SECRET_KEY);
export default async (req, res) => {
if (req.method === "POST") {
try {
const { amount } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
});
res.status(200).send(paymentIntent.client_secret);
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message });
}
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
};
try {
const { data: clientSecret } = await axios.post("/api/payment_intents", {
amount: price * 100,
});
const paymentMethodReq = await stripe.createPaymentMethod({
type: "card",
card: cardElement,
billing_details: billingDetails,
});
if (paymentMethodReq.error) {
setCheckoutError(paymentMethodReq.error.message);
setProcessingTo(false);
return;
}
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: paymentMethodReq.paymentMethod.id,
});
if (error) {
setCheckoutError(error.message);
setProcessingTo(false);
return;
}
onSuccessfulCheckout();
} catch (err) {
setCheckoutError(err.message);
}
};
you are not setting baseURL.
{ axios.post("/api/payment_intents", }
You must add some server path like localhost or wherever you are hosting API.