Apollo GraphQL server not responding when Include Cookies is turned on - node.js

Whenever I set the "Include Cookies" option as "On", the graphql server says that the server is not responding.
This works fine if the option is "Off".
Here is the index.ts
const main = async () => {
const mikroOrmConfig = {
debug: true,
user: 'postgres',
entities: [Post, User],
type: 'postgresql',
dbName: 'lireddit',
password: 'graphql',
allowGlobalContext: true,
migrations: {
path: path.join(__dirname, './migrations'),
pattern: /^[\w-]+\d+\.[tj]s$/
}
} as Parameters<typeof MikroORM.init>[0];
const orm = await MikroORM.init(mikroOrmConfig);
const app = express();
app.use(cors())
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [PostResolver, UserResolver],
validate: false
}),
context: ({ req, res }): MyContext => ({ em: orm.em, req, res })
});
await apolloServer.start();
apolloServer.applyMiddleware({ app })
app.listen(4000, () => {
console.log("Server started at port 4000")
})
};
main().catch(err => console.error(err));
I get the following error if I try to hit an API:
{
"name": "TypeError",
"message": "Failed to fetch",
}

Update:
Setting this to the server worked:
app.set('trust proxy', true)
app.use(
cors({
credentials: true,
origin: [
"https://studio.apollographql.com",
"http://localhost:4000/graphql",
],
})
);
Also, needed to attach this header in the request:

Related

Cannot set session cookie from express app into vue 3 application using axios

Link to Backend repo: https://github.com/abeertech01/session-cookies-express
Link to Frontend repo: https://github.com/abeertech01/session-cookies-vue3
Steps to reproduce:
Download and npm i repos
Run npm run dev for both repos
Navigate to: 127.0.0.1:5173
Click on Submit button, note the console message in the chrome inspector, but the cookie does NOT get saved
I want to set 'connect.sid' cookie of express-session in browser. In frontEnd I am using Vue 3.
I followed exactly everything should be added for the cookie to be saved. Maybe I am missing something. But I can't really figure out exactly what I am missing
here is my frontend code:
const submit = async () => {
try {
const { data } = await axios.post(
"http://localhost:4050/new",
{ name: "Abeer" },
{ withCredentials: true }
)
console.log(data)
} catch (error) {
console.log(error)
}
}
here it's backend code:
const express = require("express")
const session = require("express-session")
const cors = require("cors")
const app = express()
const PORT = process.env.PORT || 4050
app.use(
cors({
origin: "http://127.0.0.1:5173",
credentials: true,
})
)
app.use(express.json())
app.use(
session({
resave: false,
saveUninitialized: false,
secret: "session",
cookie: {
maxAge: 24 * 60 * 60 * 1000,
sameSite: "none",
secure: false,
},
})
)
// save a name as a cookie
app.post("/new", async (req, res) => {
try {
const name = req.body.name
req.session.name = name
res.send({ message: "saves" }).status(201)
} catch (error) {
console.log(error)
}
})
app.get("/name", async (req, res) => {
try {
console.log(req.session.name)
res.send({ message: req.session.name })
} catch (error) {
console.log(error)
}
})
app.listen(PORT, () => console.log(`Server is running on ${PORT}`))

Typescript Knex Config (!parsedConfig.client && !parsedConfig.dialect)

I am building an express backend with TypeScript, knex, postgres and heroku. Right now I am trying to connect my frontend website with the backend, to insert data into my database (pg, heroku)
I just migrated my JS files (knexfile.js, dbconfig.js) to TypeScript and didn't have the problem before. Seems to have sth. to do with my dbconfig file.
When trying to start my express server I am getting the following response: \server\node_modules\knex\lib\knex-builder\internal\config-resolver.js:20
(!parsedConfig.client && !parsedConfig.dialect)
TypeError: Cannot read properties of undefined (reading 'client')
Any idea?
files are as follows:
db-config.ts
dotenv.config();
import Knex from "knex";
const dbEnvironment = process.env.NODE_ENV || "development";
const config = require("../knexfile.ts")[dbEnvironment];
export default Knex(config);
knexfile.ts
//require("dotenv").config(); // old js
//const pg = require("pg"); //-> old js
import dotenv from "dotenv";
dotenv.config();
import pg from "pg";
import { Knex } from "knex";
if (process.env.DATABASE_URL) {
pg.defaults.ssl = { rejectUnauthorized: false };
}
const defaults = {
client: "pg",
migrations: { directory: "./db/migrations" },
seeds: { directory: "./db/seeds" },
};
const knexConfig = {
development: {
...defaults,
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
},
},
production: {
...defaults,
connection: process.env.DATABASE_URL,
pool: { min: 2, max: 10 },
},
};
const testConfig: Knex.Config = {
client: "pg",
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
},
migrations: { directory: "./db/migrations" },
seeds: { directory: "./db/seeds" },
};
export default testConfig;
index.ts
import TripService from "./api/TripService";
import * as OpenApiValidator from "express-openapi-validator";
import { HttpError } from "express-openapi-validator/dist/framework/types";
import { knex as knexDriver } from "knex";
import cors from "cors";
import testConfig from "./db/db-config";
const app = express();
const port = process.env.PORT || 5000;
const knex = knexDriver(testConfig);
const tripService = new TripService(knex);
app.use(
cors({
origin: "*", //allow requests from any origin for now
})
);
app.use(cors());
app.use(express.json());
app.use(
OpenApiValidator.middleware({
apiSpec: "./openapi.yaml",
validateRequests: true, // (default)
validateResponses: false, // false by default
})
);
app.use((err: HttpError, req: Request, res: Response, next: NextFunction) => {
// format error
res.status(err.status || 500).json({
message: err.message,
errors: err.errors,
});
});
app.post("/trips", (req, res) => {
const payload = req.body;
tripService.add(payload).then((savedTrip) => res.json(savedTrip));
});
app.get("/trips", (req, res) => {
tripService.getAll().then((savedTrips) => res.json(savedTrips));
});
app.delete("/trips/:tripId", (req, res) => {
const tripId = req.params.tripId;
tripService.delete(tripId).then(() => {
res.status(204);
res.send();
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});

Apollo client not connecting to server when Redis cookie is set

When I try to login which sets a cookie and then I refresh the page I don't get any response from apollo server and every requests made by graphql client are kept (pending) status.
After I remove a cookie, everything seems to work fine. I'm not even sure how can I debug this and have a little experience with backend so any advice would be helpful.
Here is how I setup connection from client:
const link = createHttpLink({
uri: 'http://localhost:5000/graphql',
credentials: 'include',
});
const apolloLink = ApolloLink.from([
errorLink,
link
]);
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: apolloLink,
});
And server:
useContainer(Container);
const establishDatabaseConnection = async (): Promise<void> => {
try {
await createDatabaseConnection();
} catch (error) {
console.error(error);
}
};
const initExpressGraphql = async () => {
const app = express();
const redis = new Redis();
const RedisStore = connectRedis(session);
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true,
};
const schema = await buildSchema({
resolvers: RESOLVERS,
container: Container,
});
const apolloServer = new ApolloServer({
schema: schema as GraphQLSchema,
context: ({ req, res }: any) => ({ req, res }),
introspection: true,
plugins: [
ApolloServerLoaderPlugin({
typeormGetConnection: getConnection, // for use with TypeORM
}),
],
});
app.use(
session({
store: new RedisStore({
client: redis as any,
}),
name: 'rds',
secret: 'verysecretdata',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 1000 * 60 * 60 * 24 * 7 * 365, // 7 years
sameSite: 'lax',
},
})
);
apolloServer.applyMiddleware({
app,
cors: corsOptions
})
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
};
const startServer = async (): Promise<void> => {
await establishDatabaseConnection();
initExpressGraphql();
};
startServer();
My issue got solved after I restarted redis server

My cookie is not set in Browser of studio.apollographql explorer

i am trying to set cookie on apollo Studio explorer, my redis setup successfully store the cookie, but nothing is set on the browser.
Please What am i doing wrong ?
when make a monitoring of redis with redis-cli ,i can see that the token is receive.
i am using : apollo-server-express "^3.3.0", and express-session "^1.17.2"
async function startServer() {
const app = express();
const httpServer = http.createServer(app);
const RedisStore = connectRedis(session);
const redisClient = redis.createClient({
host: "127.0.0.1",
port: 6379,
});
app.use(
session({
name: "pid",
store: new RedisStore({
client: redisClient,
}),
cookie: {
maxAge: 1000 * 60 * 10,
httpOnly: false,
secure: true,
sameSite: "none",
},
saveUninitialized: false,
secret: "EOJ7OmvIAhb2yJpCI947juj6F8CppHCp",
resave: false,
})
);
const server = new ApolloServer({
schema,
context: createContext,
formatError: (error) => {
return {
message: error.message,
};
},
});
await server.start();
server.applyMiddleware({
app,
cors: { credentials: true, origin: "https://studio.apollographql.com" },
});
await new Promise((resolve: any) =>
httpServer.listen({ port: process.env.PORT }, resolve)
);
}
startServer().catch((err) => console.log(err));

how do i access shop url and access token from multiple files?

I followed this tutorial https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react and I now have an app base which I want to develop from, however, how do I access the shop url (example.myshopify.com) and the accessToken that has been generated on server.js file from another file.
Is there a way to make shop url (example.myshopify.com) and the accessToken a global variable or send to a database so I can access them on all files? I am new to all this so not sure what I am doing.
Edit:
app.prepare().then(() => {
const server = new Koa();
server.use(session({ secure: true, sameSite: 'none' }, server));
server.keys = [SHOPIFY_API_SECRET_KEY];
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: ['read_themes', 'write_themes'],
async afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
ctx.cookies.set('shopOrigin', shop, {
httpOnly: false,
secure: true,
sameSite: 'none'
});
console.log(`${shop}`);
console.log(`${accessToken}`);
ctx.redirect('/');
},
}),
);
server.use(verifyRequest());
server.use(async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
return
});
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});

Resources