how to use createUploadLink and GraphQLWsLink in react - node.js

i'm trying to use createUploadLink and GraphQLWsLink in react is there any way
import * as dotenv from 'dotenv'
dotenv.config()
import { getUser, userProtect ,adminProtect,getAdmin} from "./Users/user.utilities.js";
import { typeDefs, resolvers } from './schema.js';
import { ApolloServer } from '#apollo/server';
import { createServer } from 'http';
import { expressMiddleware } from '#apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '#apollo/server/plugin/drainHttpServer';
import { makeExecutableSchema } from '#graphql-tools/schema';
import bodyParser from 'body-parser';
import express from 'express';
import { graphqlUploadExpress,GraphQLUpload} from "graphql-upload";
import * as path from 'path';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import { PubSub } from 'graphql-subscriptions';
const schema = makeExecutableSchema({ typeDefs, resolvers });
const app = express();
const httpServer = createServer(app);
const wsServer = new WebSocketServer({
server: httpServer,
path: '/graphql'
});
const wsServerCleanup = useServer({schema}, wsServer);
const startApolloServer = async () => {
app.use(graphqlUploadExpress())
app.use('/images', express.static(path.join(__dirname, '/uploads/images')))
const context = async ({ req }) => {
return {
LogedInUser: await getUser(req.headers.token),
LogedInAdmin: await getAdmin(req.headers.admintoken),
userProtect,
adminProtect
}
}
const server = new ApolloServer({
schema,
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
{
async serverWillStart() {
return {
async drainServer() {
await wsServerCleanup.dispose();
}
}
}
}
],
})
await server.start();
app.use('/graphql', bodyParser.json(), expressMiddleware(server,{ context }));
}
startApolloServer()
httpServer.listen(8000, () => { console.log(`🚀 Server ready at http://localhost:4000$`) })
;
i've tried this but is not working
const wsLink = new GraphQLWsLink(createClient({
url: 'ws://localhost:8000/graphql',
}));
const uploadLink = createUploadLink({
uri: "http://localhost:8000/graphql" });
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
const authLink = setContext((_,{headers })=>{
return{
headers:{
...headers,
token:localStorage.getItem(TOKEN),
admintoken:localStorage.getItem(ADMINTOKE)
}
}
})
export const client = new ApolloClient({
link:authLink.concat(splitLink) ,
cache: new InMemoryCache(),
});
i'm trying to use createUploadLink and GraphQLWsLink in react is there any way
i'm trying to use createUploadLink and GraphQLWsLink in react is there any wayi'm trying to use createUploadLink and GraphQLWsLink in react is there any way

Related

Increase body limit with nestjs & fastify

My main.ts looks like this :
import { NestFactory } from '#nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '#nestjs/platform-fastify';
import { Logger } from 'nestjs-pino';
import { processRequest } from 'graphql-upload';
import { AppModule } from './app.module';
async function bootstrap() {
const adapter = new FastifyAdapter();
const fastifyInstance = adapter.getInstance();
fastifyInstance.addContentTypeParser('multipart', (request, done) => {
request.isMultipart = true;
done();
});
fastifyInstance.addHook('preValidation', async (request: any, reply) => {
if (!request.raw.isMultipart) {
return;
}
request.body = await processRequest(request.raw, reply.raw);
});
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
adapter,
{ bufferLogs: true },
);
app.useLogger(app.get(Logger));
app.enableCors();
await app.listen(parseInt(process.env.SERVER_PORT || '3000', 10), '0.0.0.0');
}
bootstrap();
According to the fastify doc the body limit is 1MiB by default, however I want it to be larger. So I tried like this :
const adapter = new FastifyAdapter({ bodyLimit: 124857600 }); but I still get the same problem with my payload being too large.
Try to add this when you are creating the app
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({ bodyLimit: 10048576 }),

How to set cookies using apollo server express

I am using apollo server express on my backend and next js on frontend.
I have been trying to set cookies in backend using (response) from context but unfortunately it is not working. i would like your help.
here is my backend code.
import http from 'http';
import { ApolloServer } from 'apollo-server-express';
import express from 'express';
import cors from 'cors';
import { makeExecutableSchema } from '#graphql-tools/schema';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import { execute, subscribe } from 'graphql';
import {
SubscriptionServer,
ConnectionParams,
ConnectionContext,
} from 'subscriptions-transport-ws';
import { connect } from './Config';
import { typeDefs } from './TypeDefs';
import { resolvers } from './Resolvers';
import { isAuthForSubscription } from './Helpers';
import cookieParser from 'cookie-parser';
const startServer = async () => {
const app = express();
app.use(
cors({
credentials: true,
origin: 'http://localhost:3000',
})
);
app.use(cookieParser());
const httpServer = http.createServer(app);
const subscriptionServer = SubscriptionServer.create(
{
schema: makeExecutableSchema({ typeDefs, resolvers }),
execute,
subscribe,
onConnect: async (
connectionParams: ConnectionParams,
_websocket: any,
context: ConnectionContext
) => {
let user = null;
if (connectionParams.Authorization) {
user = await isAuthForSubscription(connectionParams.Authorization);
}
return { context, user };
},
},
{
server: httpServer,
path: '/graphql',
}
);
const server = new ApolloServer({
schema: makeExecutableSchema({ typeDefs, resolvers }),
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
{
serverWillStart: async () => {
return {
drainServer: async () => {
subscriptionServer.close();
},
};
},
},
],
context: ({ req, res }) => ({ req, res }),
});
await server.start();
server.applyMiddleware({ app });
await new Promise<void>(resolve =>
httpServer.listen({ port: 4000 }, resolve)
);
await connect();
console.log(
`server started on port http://localhost:4000${server.graphqlPath}`
);
return { server, app };
};
startServer();
// and my resolver is this one
import { ApolloError } from 'apollo-server-express';
import {
TCreateAccountArgs,
TLoginArgs,
TContext,
CookieName,
} from '../../__generated__';
import { generate } from '../../Helpers';
import { userModel } from '../../Models';
import { CookieOptions } from 'express';
export const login = async(_: any, args: TLoginArgs, { res, req }: TContext) => {
try {
const find = await userModel.findOne({ username: args.username });
if (!find) {
return new ApolloError('Account not found');
}
const comparePassword = generate.comparePassword(
find.password,
args.password
);
if (!comparePassword) {
return new ApolloError('Incorrect password or username');
}
const generateToken = generate.generateToken({ _id: find._id });
const cookieOptions: CookieOptions = {
httpOnly: true,
maxAge: 1 * 60 * 60 * 24 * 1000,
secure: true
};
res.cookie(CookieName.token, generateToken, cookieOptions);
return {
token: generateToken,
data: {
username: find.username,
_id: find._id,
email: find.email,
profilePicture: find.profilePicture,
createdAt: find.createdAt,
updatedAt: find.updatedAt,
},
};
} catch (error: any) {
return new ApolloError(
`Unable to login due to internal server error ${error.message}`
);
}
};
on frontend I am receiving this error message. Cannot read property 'cookie' of undefined
This question has been there from several months ago.
Just in case you haven't been able to fix it yet, the reason why you're not seeing the cookies in the frontend is that you're using the option httpOnly, those cookies are not supposed to be readable by the browser (they are useful to handle authentication in the server while protecting you from cross site scripting).
If you really need to read these cookies in the browser, you should set the httpOnly option to false.

Trouble connecting to Graphql subscriptions?

I have followed Apollo docs but seem to still be having issues connecting to subscriptions. Here is my code: On the frontend, I can see it trying to connect but is logging:
WebSocket connection to 'ws://localhost:4000/subscriptions' failed:
I have been following this: https://www.apollographql.com/docs/apollo-server/data/subscriptions/ but it seems like the documentation is slightly behind so I may be missing something.
Client:
import ReactDOM from 'react-dom';
import './index.css';
import Routes from './routes';
import 'semantic-ui-css/semantic.min.css';
import { setContext } from '#apollo/client/link/context';
import { WebSocketLink } from '#apollo/client/link/ws';
import { getMainDefinition } from '#apollo/client/utilities';
import {
ApolloProvider,
ApolloClient,
HttpLink,
InMemoryCache,
split,
} from '#apollo/client';
// Http link
const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql' });
// Websocket link
const wsLink = new WebSocketLink({
uri: 'ws://localhost:4000/subscriptions',
options: {
reconnect: true
}
});
// Attach auth headers to requests
const middlewareLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
const refreshToken = localStorage.getItem('refreshToken');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
x_token: token ? `${token}` : "",
x_refresh_token: refreshToken ? `${refreshToken}`: ""
}
}
});
// Combine
const httpLinkWithMiddleware = middlewareLink.concat(httpLink);
// Split link - either http or ws depending on graphql
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLinkWithMiddleware,
);
// Create client with link
const client = new ApolloClient({
link: splitLink,
cache: new InMemoryCache(),
});
// Provide client
const App = (
<ApolloProvider client={client}>
<Routes />
</ApolloProvider>
)
// Render
ReactDOM.render(
App,
document.getElementById('root')
);
Server:
import express from 'express';
import path from 'path';
import { fileLoader, mergeTypes, mergeResolvers } from 'merge-graphql-schemas';
import { ApolloServer } from 'apollo-server-express';
import { refreshTokens } from './auth';
import models from './models';
import cors from 'cors';
import jwt from 'jsonwebtoken';
const SECRET = "";
const SECRET2 = "";
const typeDefs = mergeTypes(fileLoader(path.join(__dirname, './schema')));
const resolvers = mergeResolvers(fileLoader(path.join(__dirname, './resolvers')));
const PORT = 4000;
const app = express();
// Cors
app.use(cors('*'));
// Add tokens
const addUser = async (req, res, next) => {
const token = req.headers['x_token'];
if (token) {
try {
const { user } = jwt.verify(token, SECRET);
req.user = user;
} catch (err) {
const refreshToken = req.headers['x_refresh_token'];
const newTokens = await refreshTokens(token, refreshToken, models, SECRET, SECRET2);
if (newTokens.token && newTokens.refreshToken) {
res.set('Access-Control-Expose-Headers', 'x_token', 'x_refresh_token');
res.set('x_token', newTokens.token);
res.set('x_refresh_token', newTokens.refreshToken);
}
req.user = newTokens.user;
}
}
next();
};
app.use(addUser);
// Create server
const server = new ApolloServer({
typeDefs,
resolvers,
subscriptions: {
path: '/subscriptions'
},
context: ({req, res, connection}) => {
const user = req.user;
return { models, SECRET, SECRET2, user };
},
});
// Apply middleware
server.applyMiddleware({ app });
// Sync and listen
models.sequelize.sync({force: true}).then(x => {
app.listen({ port: PORT }, () => {
console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`);
console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`);
}
);
});
Any help would be appreciated...
I can't see in the server declaring a websocket creation. Something like:
const WebSocket = require('ws');
const graphQLWebSocket = new WebSocket.Server({noServer: true});
Then also put in:
server.installSubscriptionHandlers(graphQLWebSocket);
After the row with server.applyMiddleware({ app });
More info here.

ReactJS(using apollo-client) not setting cookies received from ExpressJS(using apollo-server-express)

I've created simple backend api using apollo-server-express and postgresql that has two mutations: register and login. When the login mutation is used, the api creates an auth token and a refresh token and then sends them as cookies using res.cookie(...). In the frontend, I'm using apollo-client to access my GraphQL api. When I call the login mutation, everything works as expected, I receive the set-cookie header along with the requested user-details. However, the cookies don't show up in the Application tab under Cookies. Can someone please help me. I'm using the following code:
server/index.ts
import "dotenv/config";
import "reflect-metadata";
import * as express from "express";
import * as cors from "cors";
import {
ConnectionOptions,
createConnection,
getConnectionOptions
} from "typeorm";
import { buildSchema } from "type-graphql";
import { GraphQLSchema } from "graphql";
import { ApolloServer } from "apollo-server-express";
import * as path from "path";
import * as cookieParser from "cookie-parser";
import {
UserResolver,
DepartmentResolver,
CourseResolver,
SubjectResolver,
DocumentResolver
} from "./modules";
import { customAuthChecker, formatError, GQLRuntimeContext } from "./utils";
const getOptions = async () => {
console.log(`NODE_ENV: ${process.env.NODE_ENV}`);
let connectionOptions: ConnectionOptions;
connectionOptions = {
type: "postgres",
synchronize: true,
logging: false,
entities: [path.join(__dirname, "./modules/**/*entity.*")]
};
if (process.env.DATABASE_URL) {
Object.assign(connectionOptions, { url: process.env.DATABASE_URL });
} else {
// gets your default configuration
// you could get a specific config by name getConnectionOptions('production')
// or getConnectionOptions(process.env.NODE_ENV)
connectionOptions = await getConnectionOptions();
}
return connectionOptions;
};
const connect = async (): Promise<void> => {
const typeormconfig = await getOptions();
console.log(`\n`);
console.log(`\tconfiguration: `);
console.log(typeormconfig);
console.log(`\n`);
await createConnection(typeormconfig);
};
connect().then(async () => {
const schema: GraphQLSchema = await buildSchema({
resolvers: [
UserResolver,
DepartmentResolver,
CourseResolver,
SubjectResolver,
DocumentResolver
],
authChecker: customAuthChecker
});
const app: express.Application = express();
app.use(cookieParser());
const server: ApolloServer = new ApolloServer({
schema,
formatError,
context: ({ req, res }: GQLRuntimeContext): GQLRuntimeContext => ({
req,
res
})
});
server.applyMiddleware({
app,
path: "/",
cors: { origin: "*", credentials: true }
});
app.listen({ port: process.env.PORT || 4000 }, () => {
console.log(
`🚀 Server ready at http://localhost:${process.env.PORT || 4000}${
server.graphqlPath
}`
);
});
});
client/index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import {
ApolloClient,
ApolloProvider,
NormalizedCacheObject,
InMemoryCache
} from "#apollo/client";
import { createHttpLink } from "apollo-link-http";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
const link: any = createHttpLink({
uri:
/*process.env.NODE_ENV === "production"
? "https://the-notebook-graph.herokuapp.com/graphql"
: */ "http://localhost:4000/graphql",
credentials: "include"
});
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
link,
cache: new InMemoryCache()
});
ReactDOM.render(
<ApolloProvider client={client}>
<React.StrictMode>
<App />
</React.StrictMode>
</ApolloProvider>,
document.getElementById("root")
);
serviceWorker.register();
Response headers in ReactJS application
Cookies after receiving the response
I get the following error when I try to use {...credentials: "include"...} in the frontend:
Unhandled Rejection (Error): Failed to fetch

How to pass cookie from apollo-server to apollo-clenet

Mutation
Mutation: {
signUp: (_, { res }) => {
try {
res.cookie("jwt", "token", {
httpOnly: true
});
return "Amasia";
} catch (error) {
return "error";
}
};
}
Apollo-clenet-react
const [addTodo, { loading, error, data }] = useMutation(gql);
const [formSignUp, setFormSignUp] = useState({
lastName: '',
firstName: '',
password: '',
email: '',
});
const change = e => {
const { value, name } = e.target;
setFormSignUp({ ...formSignUp, [name]: value });
};
When i make a request from react.
Here is the answer I get from the server.
1)Data {"data": {"signUp": "Amasia"}}
2) Network
Application
Well when I look in Application Cookies, it is empty.
What am I doing wrong Why are cookies empty?
problem in apollo-client and apollo-server settings (apollo-cookie).
I set up like that.
apollo-client
import { render } from 'react-dom';
import React, { Suspense } from 'react';
import { ApolloClient } from 'apollo-client'
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createHttpLink } from 'apollo-link-http';
import './i18n';
import Loading from './component/loading';
import RouteProj from './router';
const link = createHttpLink({
uri: 'http://localhost:8000/graphql',
credentials: 'include'
});
const client = new ApolloClient({
cache: new InMemoryCache(),
link,
});
render(
<ApolloProvider client={client}>
<Suspense fallback={<Loading />}>
<RouteProj/>
</Suspense>
</ApolloProvider>,
document.getElementById('root'),
);
apollo-server
import cors from "cors";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import mongoose from "mongoose";
import schema from "./schema";
import resolvers from "./resolvers";
import models from "./models";
const app = express();
var corsOptions = {
origin: "http://localhost:3000",
credentials: true
};
app.use(cors(corsOptions));
const server = new ApolloServer({
typeDefs: schema,
resolvers,
context: ({ res }) => ({
res
})
});
server.applyMiddleware({ app, path: "/graphql", cors: false });
app.listen({ port: 8000 });

Resources