BadRequestError: Missing multipart field ‘operations’
See original GitHub issueMy server index.ts code :
import formidable from "formidable";
import { graphqlUploadExpress } from "graphql-upload";
import "reflect-metadata";
import {
ApolloServer,
buildSchema,
Channel,
ChannelResolver,
connectRedis,
COOKIE_NAME,
cors,
createConnection,
createMessageCreatorLoader,
createServer,
DirectMessage,
DirectMessageResolver,
express,
isProduction,
Member,
MemberResolver,
Message,
MessageResolver,
Redis,
session,
Team,
TeamResolver,
User,
UserResolver,
} from "./indexImports";
import { MyContext } from "./types/MyContext";
const PORT = process.env.PORT || 4000;
const main = async () => {
const isTestMode = !!process.env.TEST_DB;
await createConnection({
type: "postgres",
database: process.env.TEST_DB || "gignal",
username: "postgres",
password: "postgres",
logging: !isTestMode,
synchronize: !isTestMode,
entities: [User, Message, Team, Channel, Member, DirectMessage],
});
const app = express();
const RedisStore = connectRedis(session);
const redis = new Redis();
// app.set("trust proxy", 1);
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
const uploadDir = "files";
const fileMiddleware = (req, res, next) => {
if (!req.is("multipart/form-data")) {
return next();
}
const form = formidable.IncomingForm({
uploadDir,
});
form.parse(req, (error, { operations }, files) => {
console.log("next", files);
const document = JSON.parse(operations);
if (Object.keys(files).length) {
const { type, path: filePath } = files["1"];
console.log(type);
console.log(filePath);
document.variables.file = {
type,
path: filePath,
};
}
req.body = document;
next();
});
};
app.use(fileMiddleware);
app.use(
"/graphql",
graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 })
);
const sessionMiddleware = session({
name: COOKIE_NAME,
store: new RedisStore({
client: redis as any,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 366 * 10, //10 years
httpOnly: true,
sameSite: "lax", //csrf
secure: isProduction, // cookie only works in https
},
secret: "hello world",
resave: false,
saveUninitialized: false,
});
app.use(sessionMiddleware);
const schema = await buildSchema({
resolvers: [
UserResolver,
MessageResolver,
TeamResolver,
ChannelResolver,
MemberResolver,
DirectMessageResolver,
],
validate: false,
});
const apolloServer = new ApolloServer({
schema,
context: ({ req, res, connection }: MyContext) => ({
req,
res,
redis,
connection,
createMessageCreatorLoader: createMessageCreatorLoader(),
}),
subscriptions: {
path: "/subscriptions",
onConnect: async (_, { upgradeReq }: any) =>
new Promise((res) =>
sessionMiddleware(upgradeReq, {} as any, () => {
res({ req: upgradeReq });
})
),
},
});
apolloServer.applyMiddleware({
app,
cors: false,
});
const httpServer = createServer(app);
apolloServer.installSubscriptionHandlers(httpServer);
//a
httpServer.listen(PORT, () => {
console.log(`server listening on port ${PORT}`);
console.log(
`Subscriptions ready at ws://localhost:${PORT}${apolloServer.subscriptionsPath}`
);
});
};
main().catch((err) => {
console.log(err);
});
Resolver code :
@Mutation(() => Message)
@UseMiddleware(isAuth)
async createMessage(
@Arg("input") input: CreateMessageInput,
@Ctx() { req }: MyContext
) {
const { text, channelId, file } = input;
// const { createReadStream, filename } = await file;
console.log("file here", file);
const message = await Message.create({
text,
channelId,
// url: file.path,
// fileType: file.type,
creatorId: req.session.userId,
createdAt: new Date().toISOString(),
}).save();
const asyncFo = async () => {
const currentUser = await User.findOne(message.creatorId);
pubsub.publish(NEW_CHANNEL_MESSAGE, {
newMessageAdded: {
...message,
creator: currentUser,
},
});
};
asyncFo();
return message;
}
Create Message Input :
import { GraphQLUpload } from "graphql-upload";
import { Field, InputType, Int } from "type-graphql";
import { File } from "./File";
@InputType()
export class CreateMessageInput {
@Field(() => Int)
channelId: number;
@Field(() => String, { nullable: true })
text: string;
@Field(() => GraphQLUpload, { nullable: true })
file: File;
}
File :
import { Stream } from "stream";
export interface File {
filename: string;
mimetype: string;
encoding: string;
createReadStream: () => Stream;
}
Client(Next js) Code :
import { ApolloClient, InMemoryCache, split, createHttpLink } from '@apollo/client';
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";
import { setContext } from "apollo-link-context";
import { createUploadLink } from 'apollo-upload-client';
import { NextPageContext } from "next";
// import { createFileLink } from './createFileLink';
// import createUploadLink from "../utils/createUploadLink";
import createWithApollo from "./createWithApollo";
const httpLink = createUploadLink({ uri: "http://localhost:4000/graphql" });
const wsLink = process.browser
? new WebSocketLink({
uri: `ws://localhost:4000/subscriptions`,
options: {
reconnect: true,
lazy: true,
},
})
: null;
const createClient = (ctx: NextPageContext) => {
const middlewareLink = setContext(() => ({
credentials: "include",
headers: {
cookie:
typeof window === "undefined" ? ctx?.req?.headers.cookie : undefined,
},
}));
const httpLinkWithMiddleware = middlewareLink.concat(httpLink as any);
const link = process.browser
? split(
({ query }) => {
const def = getMainDefinition(query);
return (
def.kind === "OperationDefinition" &&
def.operation === "subscription"
);
},
wsLink,
httpLinkWithMiddleware as any
)
: httpLinkWithMiddleware;
return new ApolloClient({
uri: "http://localhost:4000/graphql",
link: link as any,
cache: new InMemoryCache(),
});
};
export const withApollo = createWithApollo(createClient);
I am using react-dropzone :
import { useRouter } from "next/router";
import React, { useCallback } from "react";
import { useDropzone } from "react-dropzone";
import { useCreateMessageMutation } from "../generated/graphql";
import { useGetIdFromUrl } from "../utils/hooks/useGetIdFromUrl";
interface Props {
disableClick?: boolean;
}
const FileUpload: React.FC<Props> = ({ children, disableClick }) => {
const [createMessage] = useCreateMessageMutation();
const router = useRouter();
const onDrop = useCallback(async (files) => {
console.log("files", files[0]);
const channelId = useGetIdFromUrl(router.query.channelId);
await createMessage({
variables: { input: { channelId, text: null, file: files[0] } },
});
}, []);
const handleOnClick = useCallback((e) => {
if (disableClick) {
e.stopPropagation();
}
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
});
const outlineStyle = isDragActive
? {
outlineColor: "lightgray",
outlineStyle: "dashed",
}
: {};
const disableClickStyle =
disableClick && !isDragActive ? { outline: "none" } : {};
const style = { ...outlineStyle, ...disableClickStyle };
return (
<div
{...getRootProps({
style: { ...style, height: "100%" },
onClick: handleOnClick,
})}
>
<input {...getInputProps()} />
{children}
</div>
);
};
export default FileUpload;
When i submit file it created in /files directory but I got this error : BadRequestError: Missing multipart field ‘operations’
Issue Analytics
- State:
- Created 3 years ago
- Comments:7 (3 by maintainers)
Top Results From Across the Web
BadRequestError: Missing multipart field 'operations' #115
Hello there, I've been struggling to get apollo-upload-server working in my local environment, along side apollo-upload-client inside my ...
Read more >Relay Modern BadRequestError: Missing multipart field ...
js for uploading it server throws following error. BadRequestError: Missing multipart field 'operations' (https://github.com/jaydenseric/graphql ...
Read more >File uploads - graphql-compose
apollo-upload-server - for parsing multipart/form-data POST requests via busboy and providing File s data to resolve function as argument. Tutorial. 1.
Read more >Missing multipart field 'operations' with graphql-upload and ...
Coding example for the question Missing multipart field 'operations' with graphql-upload and apollo-server-node.js.
Read more >File Upload - gqlgen
Graphql server has an already built-in Upload scalar to upload files using a multipart request. It implements the following spec ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Please refer to Apollo for support with using Apollo Server; none of your problems have anything to do with a bug in this package.
Piece of advice; follow the example (adjusting for Express, vs Koa) for setting up
graphql-upload
with Apollo Server:https://github.com/jaydenseric/apollo-upload-examples/blob/be1444a0aa8768c6fe2e2c96119eb2b6344fcc50/api/server.js#L78-L81
Note that you need to disable their outdated file upload support and set it up yourself.
Good luck!
Yeah,you are true. I do what you said.And that works,thanks for your help !