I'm trying to switch out express-graphql to apollo-server v2 but I'm having difficult time migrating packages, especially with passportjs and session.
My current set up with express-graphql:
const schema = include('schema')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
secret: process.env.SESSION_SECRET,
name: 'sessionId',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
}))
app.use(passport.initialize())
app.use(passport.session())
app.use('/graphql', expressGraphQL({ schema }))
const server = http.createServer(app)
server.listen(8000, '0.0.0.0', () =>
console.log('Server running on port 8000')
)
And now with apollo-server-express#rc:
const schema = include('schema')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
secret: process.env.SESSION_SECRET,
name: 'sessionId',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
}))
app.use(passport.initialize())
app.use(passport.session())
const apollo = new ApolloServer({
schema,
context: ({ req: { user, session } }) => ({ user, session })
})
apollo.applyMiddleware({ app, path: '/graphql' })
server.listen(8000, '0.0.0.0', () =>
console.log('Server running on port 8000')
)
With this, I'm getting user and session objects in context and works like before but when I try to login() or logout() users via context it says login is not a function.
Ok so in context, context: ({ req: { user, session, login, logout } }) => ({ user, session, login, logout }) and try again, but now I'm getting Passport is not initialized
Before I didn't have to set context with express-graphql so that's where I'm stuck. Please help?
Related
I want to apply prefixes to all types, mutations, etc. in GQL schema generated. Here is my config factory:
useFactory: (configService: ConfigService) => ({
autoSchemaFile: 'schema.graphql',
sortSchema: true,
// eslint-disable-next-line #typescript-eslint/explicit-function-return-type
transformSchema: schema => wrapSchema({
schema,
transforms: [
new RenameTypes(name => `New${name}`),
new RenameObjectFields((_, fieldName) => `new_${fieldName}`),
new RenameInterfaceFields((_, fieldName) => `new_${fieldName}`),
new RenameInputObjectFields((_, fieldName) => `new_${fieldName}`),
],
}),
playground: configService.get<string>('NODE_ENV') === 'development',
context: ({ req, res }): { req: Request; res: Response } => ({
req,
res,
}),
tracing: configService.get<string>('NODE_ENV') === 'development',
}),
wrapSchema works fine but as a result I'm still getting old schema... It seems like transformSchema is not working at all. How to fix it?
So, after exploring the source code of #nestjs/graphql I found out that in order to make transformSchema option work I have to set transformAutoSchemaFile: true because I use autoSchemaFile.
For my project, I'm utilizing AWS Lambda and Graphql. I used apollo-server-lambda for this project. For this project, I created custom headers. And I added a simple condition to throw an error if there is no 'event.headers.authorization'. When the app is launched in a local environment, the error is thrown correctly. But the issue is that I'm not sure how I'm going to put my authorisation in if it's continuously throwing me off. I'm certain my implementation is incorrect. I'm not sure what the best method is for obtaining authorization.
It should be put like this:
.
This is my Lambda
import * as R from 'ramda';
import { AuthenticationError, ForbiddenError } from 'apollo-server-lambda';
export const authToken = (token: string) => {
if (token === 'HELLO') {
return true;
} else {
throw new AuthenticationError('No authorization header supplied');
}
};
const lambda =
(lambdaFunc: AWSLambda.Handler): AWSLambda.Handler =>
(event, context, callback) => {
const { authorization } = event.headers;
if (R.isNil(authorization))
throw new ForbiddenError('You must be authenticated'); // always thorws me error
return authToken(event.headers.authorization);
return lambdaFunc(event, context, callback);
};
export default lambda;
This is my graphql
import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core';
import { ApolloServer} from 'apollo-server-lambda';
import schema from '../graphql/schema';
import resolvers from '../resolvers';
import lambda from '../utils/lambda';
const server = new ApolloServer({
typeDefs: schema,
resolvers,
debug: false,
plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
introspection: true,
});
export default lambda(
server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: '*',
credentials: true,
allowedHeaders: ['Content-Type', 'Origin', 'Accept', 'authorization'],
optionsSuccessStatus: 200,
maxAge: 200,
exposedHeaders: ['authorization'],
},
},
})
);
This is YAML file
functions:
graphql:
handler: src/handlers/graphql.default
events:
- http:
path: ${env:api_prefix}/graphql
method: get
cors: true
- http:
path: ${env:api_prefix}/graphql
method: post
cors: true
My question is how can i set this graphql playground extension as my default playground instead of using the default sandbox when i visited http://hocalhost/port/graphql. Is there any option that i can set during the creation of the ApolloServer instance that can configure that?.
...
const apolloServer = new ApolloServer({
schema: await buildSchema({
validate: false,
resolvers: [HelloResolver, UserResolver],
}),
context: ({ req, res }) => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
....
Use the GraphQL Playground plugin and provide it to your Apollo Server constructor. For more info checkout Apollo Docs.
import {
ApolloServerPluginLandingPageGraphQLPlayground
} from "apollo-server-core";
const apolloServer = new ApolloServer({
...
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
});
I have problem regarding on my authentication after I login there is prompt localhost:8000 login or Sign in, this is the first time I encounter this, I don't know what this called, i don't find any reference for this. currently I am using laravel for the backend and vue js for front end. so this project created by old developer. so now I need to revise some module on there project, however i Login on the system in shows this prompt. note that this project is currently working and there is no error and prompt login when I login.
Here is prompt sign shown after I login.
Configuration:
Laravel Passport
Vuex For State Management
Vue Js
METHOD:
methods:{
authenticate(){
this.login_alert = false
this.$validator.validateAll().then((result)=>{
if(result){
const self = this;
const authUser = {}
try{
const data = {
username: this.email,
password: this.password,
remember: this.remember_me,
client_id: '2',
client_secret: 'just secret only',
grant_type : 'password',
scope : ''
}
this.$store.dispatch('AUTH_REQUEST',data)
.then(response=>{
authUser.access_token = response.access_token
authUser.refresh_token = response.refresh_token
authUser.expires_in = response.expires_in
window.localStorage.setItem('project_token',JSON.stringify(authUser))
/*LOGIN*/
this.login_alert = false
this.loading = false
window.location.reload()
})
.catch(error=>{
this.login_alert = true
window.localStorage.removeItem('project_token')
this.loading = false
})
}catch(err){
console.log(err);
}
}
})
}
},
AUTH REQUEST:
AUTH_REQUEST:({commit,dispatch},obj)=>{
return new Promise((resolve,reject) => {
axios({
url: '/oauth/token',
data: obj,
method:'post',
config:'JSON'
})
.then(response=>{
if(response.status == 200){
resolve(response.data);
}
})
.catch(error=>{
reject(error);
localStorage.removeItem('project_token');
commit('AUTH_ERROR',error);
})
})
},
Hope someone can help me to solve this problem.
Thank you.
I'm trying to check for internet connectivity using apollo websockets, the purpose of this is to show a "you're disconnected" message when there is no connection to prevent the user from typing and assuming the changes are saved (the changes are supposedly saved on type), here's part of the setup of apollo-link-ws
const wsLink = new WebSocketLink({
uri: `ws://${hostname}${port ? `:${port}` : ''}/subscriptions`,
options: {
reconnect: true,
connectionParams: () => ({
authorization: localStorage.getItem('accelerator-token')
})
}
});
and
const hasSubscriptionOperation = ({ query: { definitions } }) =>
definitions.some(
({ kind, operation }) =>
kind === 'OperationDefinition' && operation === 'subscription'
);
and here's the client config:
const client = new ApolloClient({
link: ApolloLink.split(
hasSubscriptionOperation,
wsLink,
ApolloLink.from([
cleanTypenameLink,
authMiddleware,
errorLink,
stateLink,
createUploadLink()
])
),
cache
});
After some searching i found that i can use SubscriptionClient from subscriptions-transport-ws
export const myClient = new SubscriptionClient(`ws://${hostname}${port ?
`:${port}` : ''}/subscriptions`, {
reconnect: true,
connectionParams: () => ({
authorization: localStorage.getItem('accelerator-token')
})
});
myClient.onConnected(()=>{console.log("connected f client f onConnected")})
myClient.onReconnected(()=>{console.log("connected f client f
reconnected")})
myClient.onReconnecting(()=>{console.log("connected f client f
reconnecting")})
myClient.onDisconnected(()=>{console.log("connected f client f
onDisconnected")})
myClient.onError(()=>{console.log("connected f client f onError")})
export const wsLink = new WebSocketLink(myClient);
These methods can be used to detect the network status
If you are working with React I found this nice community package react-apollo-network-status