types error after updating to v1.0.0-next.2
HT-Moh opened this issue · comments
HT-Moh commented
Trying to update the nextjs upload API after updating next-connect to the last version but getting two types errors:
First type error
Type 'NextApiRequest' is missing the following properties from type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>': get, header, accepts, acceptsCharsets, and 23 more.ts(2345)
Second type error:
Types of parameters 'request' and 'args_0' are incompatible.
Property 'file' is missing in type 'NextApiRequest' but required in type 'NextApiRequestExtended'.ts(2
Code before the update
import * as mime from 'mime-types'
import multer, { MulterError } from 'multer'
import { NextApiRequest, NextApiResponse } from 'next'
import nextConnect from 'next-connect'
import withAuth, { HASURA_ROLE } from '@/middlewares/withAuth'
export const config = {
api: {
bodyParser: false, // Disallow body parsing, consume as stream
},
}
interface NextApiRequestExtended extends NextApiRequest {
file: any
}
const upload = multer({
storage: multer.diskStorage({
destination: (request, file, callback) => {
const destinationPath =
request.query.isProjectPic === 'true'
? `./public/uploads/project`
: `./public/uploads/profile`
callback(null, destinationPath)
},
filename: (request, file, callback) => {
const extension = mime.extension(file.mimetype)
if (typeof extension === `string`) {
const fileNames = file.originalname.split('.', 1)
const { userId } = request.query
if (fileNames.length > 0) {
const fileName = fileNames[0]
.toLowerCase()
.replace(/\s/g, '-')
// eslint-disable-next-line unicorn/prefer-spread
.concat('-', userId ? (userId as string) : '', '.', extension)
callback(null, fileName)
return
}
}
callback(null, file.originalname)
},
}),
limits: { fileSize: 2 * 1024 * 1024 },
fileFilter: (request, file, callback) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
callback(null, true)
} else {
return callback(new Error('Invalid mime type'))
}
},
})
const apiRoute = nextConnect({
onError(error, request: NextApiRequest, response: NextApiResponse) {
return response.status(501).json(error)
},
onNoMatch(request, response) {
return response
.status(405)
.json({ error: `Method '${request.method}' Not Allowed` })
},
})
apiRoute.use(upload.single('image-upload'))
apiRoute.post(async (request: NextApiRequestExtended, response) => {
try {
if (!request.file) {
response.statusCode = 400
return response.status(404).end('File was not provided')
}
const file = request.file
response.status(200).send({
filename: file.filename,
size: file.size,
path: file.path,
})
} catch (error: any) {
return response.status(404).end((error as MulterError).message)
}
})
export default withAuth(apiRoute, HASURA_ROLE.USER)
code after update
/* eslint-disable unicorn/no-null */
import * as mime from 'mime-types'
import multer, { MulterError } from 'multer'
import { NextApiRequest, NextApiResponse } from 'next'
import { createRouter } from 'next-connect'
import withAuth, { HASURA_ROLE } from '@/middlewares/withAuth'
export const config = {
api: {
bodyParser: false, // Disallow body parsing, consume as stream
},
}
interface NextApiRequestExtended extends NextApiRequest {
file: any
}
const upload = multer({
storage: multer.diskStorage({
destination: (request, file, callback) => {
const destinationPath =
request.query.isProjectPic === 'true'
? `./public/uploads/project`
: `./public/uploads/profile`
callback(null, destinationPath)
},
filename: (request, file, callback) => {
const extension = mime.extension(file.mimetype)
if (typeof extension === `string`) {
const fileNames = file.originalname.split('.', 1)
const { userId } = request.query
if (fileNames.length > 0) {
const fileName = fileNames[0]
.toLowerCase()
.replace(/\s/g, '-')
// eslint-disable-next-line unicorn/prefer-spread
.concat('-', userId ? (userId as string) : '', '.', extension)
callback(null, fileName)
return
}
}
callback(null, file.originalname)
},
}),
limits: { fileSize: 2 * 1024 * 1024 },
fileFilter: (request, file, callback) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
callback(null, true)
} else {
return callback(new Error('Invalid mime type'))
}
},
})
const router = createRouter<NextApiRequest, NextApiResponse>()
router
.use(upload.single('image-upload'))
.post(
async (request: NextApiRequestExtended, response: NextApiResponse<any>) => {
try {
if (!request.file) {
response.statusCode = 400
return response.status(404).end('File was not provided')
}
const file = request.file
response.status(200).send({
filename: file.filename,
size: file.size,
path: file.path,
})
} catch (error: any) {
return response.status(404).end((error as MulterError).message)
}
},
)
const apiRoute = router.handler({
onError(error, request: NextApiRequest, response: NextApiResponse) {
return response.status(501).json(error)
},
onNoMatch(request, response) {
return response
.status(405)
.json({ error: `Method '${request.method}' Not Allowed` })
},
})
export default withAuth(apiRoute, HASURA_ROLE.USER)
HT-Moh commented
Actually, this library is not needed anymore :-)
/* eslint-disable unicorn/no-null */
import * as mime from 'mime-types'
import multer from 'multer'
import { NextApiRequest, NextApiResponse } from 'next'
import withAuth, { HASURA_ROLE } from '@/middlewares/withAuth'
export const config = {
api: {
bodyParser: false, // Disallow body parsing, consume as stream
},
}
interface NextApiRequestExtended extends NextApiRequest {
file: any
files: any
}
const upload = multer({
storage: multer.diskStorage({
destination: (request, file, callback) => {
const destinationPath =
request.query.isProjectPic === 'true'
? `./public/uploads/project`
: `./public/uploads/profile`
callback(null, destinationPath)
},
filename: (request, file, callback) => {
const extension = mime.extension(file.mimetype)
if (typeof extension === `string`) {
const fileNames = file.originalname.split('.', 1)
const { userId } = request.query
if (fileNames.length > 0) {
const fileName = fileNames[0]
.toLowerCase()
.replace(/\s/g, '-')
// eslint-disable-next-line unicorn/prefer-spread
.concat('-', userId ? (userId as string) : '', '.', extension)
callback(null, fileName)
}
}
callback(null, file.originalname)
},
}),
limits: { fileSize: 2 * 1024 * 1024 },
fileFilter: (request, file, callback) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
callback(null, true)
} else {
return callback(new Error('Invalid mime type'))
}
},
})
// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(
request: NextApiRequestExtended,
response: NextApiResponse,
function_: any,
) {
return new Promise((resolve, reject) => {
function_(request, response, (result: any) => {
if (result instanceof Error) {
return reject(result)
}
return resolve(result)
})
})
}
const handler = async (
request: NextApiRequestExtended,
response: NextApiResponse,
) => {
try {
await runMiddleware(request, response, upload.single('image-upload'))
if (!request.file) {
response.statusCode = 400
return response.status(404).end('File was not provided')
}
const file = request.file
response.status(200).send({
filename: file.filename,
size: file.size,
path: file.path,
})
} catch (error: any) {
return response.status(404).end(error.message)
}
}
export default withAuth(handler, HASURA_ROLE.USER)