I am trying to utilize formidable to access a file and eventually post it to a file storage system by following this post: Create upload files api in next.js. I am logging the data, but am getting confused about the output. When I try and access data.files.resume.filepath I get undefined.
The data looks like:
{ fields: {}, files: { resume: [ [PersistentFile] ] } }
And when I log data.files.resume I get this which shows the filepath:
[
PersistentFile {
_events: [Object: null prototype] { error: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
lastModifiedDate: 2023-02-09T01:59:50.924Z,
filepath: 'C:\\Users\\Me\\AppData\\Local\\Temp\\21eef37a9191459ae49bb110f',
newFilename: '21eef37a9191459ae49bb110f',
originalFilename: 'thankyou.pdf',
mimetype: 'application/pdf',
hashAlgorithm: false,
size: 57285,
_writeStream: WriteStream {
fd: null,
path: 'C:\\Users\\Me\\AppData\\Local\\Temp\\21eef37a9191459ae49bb110f',
flags: 'w',
mode: 438,
start: undefined,
pos: undefined,
bytesWritten: 57285,
closed: false,
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kFs)]: [Object],
[Symbol(kIsPerformingIO)]: false,
[Symbol(kCapture)]: false
},
hash: null,
[Symbol(kCapture)]: false
}
]
and when I log the data.files.resume.filepath I get undefined
Front End Form Submit:
const formData = new FormData();
formData.append("resume", resume);
const response = await fetch("/api/apply", {
method: "POST",
body: formData,
});
NextJS API:
import type { NextApiRequest, NextApiResponse } from "next";
import { IncomingForm } from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return;
}
// parse form with a Promise wrapper
const data = await new Promise((resolve, reject) => {
const form = new IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) return reject(err);
resolve({ fields, files });
});
});
console.log("------");
console.log(data);
console.log("------");
console.log(data.files.resume);
console.log("------");
console.log(data.files.resume.filepath); // this logs undefined
res.status(200).json(data);
}
I followed this StackOverflow article: Create upload files api in next.js and have tried logging each step, but still get undefined for the filepath. Any help or guidance is greatly appreciated!
Related
I build an applicant with Redux RTK with createEntity
Two issue that I couldn't found it on the docs
CreateEntity is only return {ids: [], entities: []}? Is possible that return eg: totalPage from the response also?
Cache page only work on the hardcode initialState in createSlice if the pageQuery is same.
First question:
Getting the response from server was
{
users: [{id: 1}, ...]
totalPage: 100
}
I'd like to send totalPage to auto generated hook also.
export const usersAdapter = createEntityAdapter({})
export const initialState = usersAdapter.getInitialState()
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query({
query: (args) => {
return {
url: '/api/users',
method: 'GET',
params: { page: 1, limit: 10 }
}
},
validateStatus: (response, result) => {
return response.status === 200 && !result.isError
},
transformResponse: (responseData) => {
const loadedUsers = responseData?.users.map((user) => user)
console.log("responseData: ", responseData) // <----- return { users: [], totalPage: 100 }. Could we set this totalPage value into Adapter?
return usersAdapter.setAll(initialState, loadedUsers)
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id) => ({ type: "User", id })),
]
} else return [{ type: "User", id: "LIST" }]
},
})
})
})
Use the hook in component
const { data } = useGetUsersQuery("page=1&limit=10");
console.log(data) // { ids: [], entity: [{}, {}] };
// expected return { ids: [], entity: [{}, {}], totalPage: 100}
Second question:
Store the page query in createSlice. The edit page will be remain same after refresh if the page query value same as initialState value.
import { createSlice } from "#reduxjs/toolkit"
const userReducer = createSlice({
name: "user",
initialState: {
query: `page=1&limit=10`,
},
reducers: {
setUserPageQuery: (state, action) => {
const query = action.payload
state.query = query
},
},
})
Page url Flow:
localhost:3000/users > localhost:3000/users/4 > refresh -> data will remain after refresh browser. (query "page=1&limit10" same as createSlice initialState value )
localhost:3000/users > localhost:3000/users/15 > refresh -> data state will gone after refresh browser. (query "page=2&limit10" different from createSlice initialState value )
Appreciate all the reply :)
The validate function for basic
await server.register(require('#hapi/basic'));
const validate = async (request, email, password, id_customer) => {
console.log(request)
if (!email || !password || !id_customer) {
return { credentials: null, isValid: false };
}
const results = await getHash(id_customer);
if (results.length == 0) {
return { credentials: null, isValid: false };
}
if (bcrypt.compareSync(password, results[0]['passwd'])) {
const credentials = { id: id_customer, email: email };
return { isValid: true, credentials };
}
return { credentials: null, isValid: false };
};
server.auth.strategy('simple', 'basic', { validate });
Route example :
{
method: 'POST',
path: '/home/getCategories',
config: {
auth: 'simple',
description: 'Get Home',
payload: {
multipart: true
},
handler: Home.getCategories
},
/* options: {
auth: 'simple'
},*/
//handler: Home.getCategories
},
Here is the axios call from the App :
axios.post('https://api.domain.com/home/getCategories', {
code: code
},
{
headers: {
'email': email,
'password': password,
'id_customer': id_customer
},
})
When I do the call I got a 401 unauthorized but I cant see the output of 'console.log(request)'
Any help ?
Have you tried the following? What version of Hapi.js are you using?
const categoryPostValidation = {
payload: Joi.object({
name: Joi.string().label("Name").min(1).max(30).error((errors) => new Error('Name is invalid, and must be 1 to 30 characters in length')).required(),
description: Joi.string().label("Description").min(1).max(255).error((errors) => new Error('Description is invalid, and must be 1 to 255 characters in length')).required()
}),
failAction: async (request, h, err) => {
throw err;
}
};
const categoryPostRouteOptions = {
description: "Posts one category.",
cors: true,
payload: {
output: 'data', // These are default options
parse: true // These are default options
},
auth: {
mode: 'required' // or 'try', etc
strategy: 'simple'
},
validate: categoryPostValidation,
handler: Home.getCategories
};
{
method: 'POST',
path: '/home/getCategories',
options: categoryPostRouteOptions
},
i'm stuck while converting an old project to redux tool kit getting an "Unhandled Rejection (TypeError): state.push is not a function" error. i haven't got to grips with the action/thunk and reducer immutability yet. The alerts are working but then the error msg.
import axios from 'axios';
import { setAlert } from '../alerts/alertSlice';
const slice = createSlice({
name: 'auth',
initialState: {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null,
},
reducers: {
registerSuccess: (state, action) => {
const { payload } = action.payload;
state.push({
payload,
isAuthenticated: true,
loading: false,
});
},
registerFail: (state, action) => {
localStorage.removeItem('token');
state.push({
token: null,
isAuthenticated: false,
loading: false,
user: null,
});
},
},
});
const { registerSuccess, registerFail } = slice.actions;
export default slice.reducer;
// Register User
export const register =
({ name, email, password }) =>
async (dispatch) => {
const config = {
headers: {
'comtent-Type': 'application/json',
},
};
const body = JSON.stringify({ name, email, password });
try {
const res = await axios.post('/api/users', body, config);
dispatch({
type: registerSuccess,
payload: res.data,
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch(registerFail());
}
};
.push is an array function to add a new item at the end of an array - your state is not an array.
You probably wanted to do something along the lines of
state.token = null
state.isAuthenticated = false
state.loading = false
state.user = null
What I want
I want to change pages without next thinking I am trying to open another page.
The Problem
I have this weird routing problem.
First, my folder structure
pages
[app]
[object]
index.js
index.js
manager.js
feed.js
I am at this path /[app] and navigate to /[app]/manager and then I want to navigate to /[app]/feed and I get this Unhandled Runtime Error.
TypeError: Cannot read property "title" of undefined
This error comes from [object] index.js. Stacktrace is below. Of course, it makes sense it cannot read title because I am trying to open another page. And yet it thinks I am trying to open [object].
This error happens from time to time, but it doesn't matter in what order I try to open the pages, it can be manager to feed or feed to manager, or whatever else I have there.
My getStaticPaths and getStaticProps are the same on all these pages, I will share the one for manager.js.
export const getStaticPaths = async () => {
const paths = appRoutes.map((appRoute) => {
const slug = appRoute.slug;
return {
params: {
app: slug,
manager: 'manager',
},
};
});
return {
fallback: false,
paths,
};
};
export const getStaticProps = async ({ locale }) => {
return {
props: {
...(await serverSideTranslations(locale, ['manager', 'common'])),
},
};
};
And the same again, but for [object]:
export const getStaticPaths = async () => {
const allObjects = await loadObjectData({ id: 'all' });
const paths = allObjects.flatMap((object) => {
return appRoutes.map((appRoute) => {
return {
params: {
object: object.type,
app: appRoute.slug,
},
};
});
});
return {
fallback: false,
paths,
};
};
export const getStaticProps = async ({ params, locale }) => {
const object = await loadObjectData({ type: params.object });
const app = appRoutes.find((appRoute) => appRoute?.slug === params.app);
if (!object) {
throw new Error(
`${object} is not a valid Object. Try checking out your parameters: ${params.object}`
);
}
if (!app) {
throw new Error(`${app} is not a valid App.`);
}
return {
props: {
...(await serverSideTranslation(locale, ['common'])),
object,
app,
},
};
};
This error is hard to reproduce because it happens only from time to time.
New Edits
This is the full file of [object]/index.js
import appRoutes from '../../../routes/appRoutes';
import loadObjectData from '../../../utils/loadObjects';
import { serverSideTranslation } from 'next-i18next/serverSideTranslations';
export default function ObjectPage({ object }) {
return <h1> {object.title} </h1>;
}
export const getStaticPaths = async () => {
const allObjects = await loadObjectData({ id: 'all' });
const paths = allObjects.flatMap((object) => {
return appRoutes.map((appRoute) => {
return {
params: {
object: object.type,
app: appRoute.slug,
},
};
});
});
return {
fallback: false,
paths,
};
};
export const getStaticProps = async ({ params, locale }) => {
const object = await loadObjectData({ type: params.object });
const app = appRoutes.find((appRoute) => appRoute?.slug === params.app);
if (!object) {
throw new Error(
`${object} is not a valid Object. Try checking out your parameters: ${params.object}`
);
}
if (!app) {
throw new Error(`${app} is not a valid App.`);
}
return {
props: {
...(await serverSideTranslation(locale, ['common'])),
object,
app,
},
};
};
Stacktrace:
ObjectPage: index.js:6 Uncaught TypeError: Cannot read property 'title' of undefined
at ObjectPage (http://localhost:3000/_next/static/chunks/pages/%5Bapp%5D/%5Bobject%5D.js:3733:21)
at div
at Grid (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:13654:35)
at WithStyles (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:179881:31)
at div
at StyledComponent (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:179652:28)
at div
at ProjectSelectionStore (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:234820:77)
at Layout (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:278:23)
at TaskStore (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:235454:77)
at UserDocumentStore (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:235663:77)
at StoneStore (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:235119:77)
at StoreMall (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:409:23)
at ThemeProvider (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:178584:24)
at App (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:234333:24)
at I18nextProvider (http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1624290251377:224427:19)
at AppWithTranslation
at ErrorBoundary (http://localhost:3000/_next/static/chunks/main.js?ts=1624290251377:146:47)
at ReactDevOverlay (http://localhost:3000/_next/static/chunks/main.js?ts=1624290251377:250:23)
at Container (http://localhost:3000/_next/static/chunks/main.js?ts=1624290251377:8662:5)
at AppContainer (http://localhost:3000/_next/static/chunks/main.js?ts=1624290251377:9151:24)
at Root (http://localhost:3000/_next/static/chunks/main.js?ts=1624290251377:9282:24)
25.06.2021
So I consoled logged the router from the ObjectPage and for each NavigationItem. I noticed something strange.
This is the href I am passing to teh <Link>:
{
pathname: "/[app]/[menuItem]"
query: {
app: "content"
menuItem: "files"
}
}
And this is the full router I am getting back on ObjectPage.
{
asPath: "/content/editor" // this the path i want to open
back: ƒ ()
basePath: ""
beforePopState: ƒ ()
components: {
"/[app]/[object]": {styleSheets: Array(0), __N_SSG: true, __N_SSP: undefined, props: {…}, Component: ƒ}
"/[app]/editor": {initial: true, props: {…}, err: undefined, __N_SSG: true, Component: ƒ, …}
"/_app": {styleSheets: Array(0), Component: ƒ}
}
defaultLocale: "de"
events: {on: ƒ, off: ƒ, emit: ƒ}
isFallback: false
isLocaleDomain: false
isPreview: false
isReady: true
locale: "de"
locales: ["de"]
pathname: "/[app]/[object]" // [object] is being loaded
prefetch: ƒ ()
push: ƒ ()
query: {app: "content", menuItem: "editor", object: "editor"} // this is interesting
reload: ƒ ()
replace: ƒ ()
route: "/[app]/[object]" // same as pathname
}
In the query you can see object was injected. But I cannot tell from where and why.
I had this code:
{
pathname: "/[app]/[menuItem]"
query: {
app: "content"
menuItem: "files"
}
}
This was incorrect because there is no dynamic path to [menuItem]. So instead I wrote:
{
pathname: "/[app]/files"
query: {
app: "content"
}
}
Which fixed the issue I had.
I have misunderstood the docs for parameters.
I want to upload a batch of 64 images to Custom Vision using the JavaScript SDK.
const files: ImageFileCreateEntry[] = []
while (i < 64) {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
i++
}
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
But I'm getting the following error:
RestError: No valid image files
at new RestError (/home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/restError.ts:18:5)
at /home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/policies/deserializationPolicy.ts:117:27
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 5) {
code: 'BadRequestImageBatch',
statusCode: 400,
request: WebResource {
streamResponseBody: false,
url: 'https://eastus.api.cognitive.microsoft.com/customvision/v3.3/training/projects/ff4967f9-f772-4473-89a5-41356c471454/images/files',
method: 'POST',
headers: HttpHeaders { _headersMap: [Object] },
body: '{"images":[],"tagIds":["8a2e95b5-2050-403d-95e7-45b08e358d7d"]}',
query: undefined,
formData: undefined,
withCredentials: false,
abortSignal: undefined,
timeout: 0,
onUploadProgress: undefined,
onDownloadProgress: undefined,
proxySettings: undefined,
keepAlive: undefined,
operationSpec: {
httpMethod: 'POST',
path: 'projects/{projectId}/images/files',
urlParameters: [Array],
requestBody: [Object],
responses: [Object],
serializer: [Serializer]
}
},
response: {
body: '{"code":"BadRequestImageBatch","message":"No valid image files"}',
headers: HttpHeaders { _headersMap: [Object] },
status: 400
},
body: { code: 'BadRequestImageBatch', message: 'No valid image files' }
}
I figured out that my implementation was completely messed up.
This is how I solved it for now:
const client = getTrainingClient();
const tags = await client.getTags(projectId);
let fileUploadPromises = [];
tags.forEach(tag => {
const imageFiles = fs.readdirSync(`${sampleDataRoot}/${tag.name}`);
const files: ImageFileCreateEntry[] = []
const chunk = imageFiles.slice(0, 64)
chunk.forEach(file => {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
})
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
})