Swagger UI not getting generated for serverless Express api - express

My code structure is as follows-
src
-handler.ts
-routes
--user.ts
serverless.yml
node_modules
..etc
Code in 'handler.ts' for is as follows-
import express, { Express, Request, Response, NextFunction } from "express";
import serverless from "serverless-http";
import userRouter from "./routes/user";
import cookieParser from "cookie-parser";
import swaggerUi = require('swagger-ui-express');
import swaggerJsDoc = require('swagger-jsdoc');
const app: Express = express();
app.use(express.json());
app.use(cookieParser());
const swaggerOptions = {
swaggerDefinition: {
info: {
version: "1.0.0",
title: "User service",
description: "user service APIs",
contact: {
name: "Sid"
}
}
},
apis: ["./routes/*.ts"]
};
const swaggerDocs = swaggerJsDoc(swaggerOptions);
app.use('/swagger',swaggerUi.serve, swaggerUi.setup(swaggerDocs,{
swaggerOptions: {
url: "api-docs"
},
}));
app.use('/', userRouter);
module.exports.handler = serverless(app);
After I deploy this lambda using the serverless, my APIs are working fine the swagger-ui URL is not working. Please help

Related

Resolving Keycloak Client Adapter Deprecation for Node.js Express Boilerplate using Passport with OpenID Connect Client

I had previously built a Keycloak Express boilerplate using the node client adapter (keycloak-connect). However, Keycloak has deprecated their client adapters for node, so I looked for a solution and found a suggestion to integrate Passport with the OpenID Client for Keycloak on this Stack Overflow question (NodeJS + Keycloak without express). I followed the instructions in this Medium article (https://medium.com/keycloak/keycloak-express-openid-client-fabea857f11f) to build my Keycloak Express boilerplate, but it didn't work for me. My register and login endpoints are functioning properly, but my protected route is not working as expected.Could anyone provide a template or guide on how to properly configure Passport.js? I have attached my current code for reference.
import express, {
Express,
Request,
Response
} from 'express';
import 'reflect-metadata';
import bodyparser from 'body-parser';
import userRouter from './api/routes/userRoutes';
import expressSession from 'express-session';
import cookieParser from 'cookie-parser'
import connection from './database/connection';
import cors from 'cors';
import { corsOptions } from './config/corsOptions';
import { credentials } from './api/middlewares/credentials';
import { Issuer, Strategy } from 'openid-client';
import passport from 'passport';
import config from './config';
import KeycloakStrategy from "#exlinc/keycloak-passport";
//GETTING PORT FROM .ENV FILE:
const PORT = config.port || 3000;
const app: Express = express();
var memoryStore = new expressSession.MemoryStore();
app.use(
expressSession({
secret: 'another_long_secret',
resave: false,
saveUninitialized: true,
store: memoryStore
})
);
app.use(passport.initialize());
app.use(passport.authenticate('session'));
Issuer.discover('http://localhost:8080/realms/Demo').then(function (oidcIssuer) {
var client = new oidcIssuer.Client({
client_id: 'keycloak_practice',
client_secret: 'hkvogjo7jziNV3X4hR2rUILQikNKHpSL',
redirect_uris: ['http://localhost:8000/private'],
response_types: ['code'],
})
passport.use('oidc', new Strategy({client}, (tokenSet, userinfo, done)=>{
return done(null, tokenSet.claims());
})
)
});
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
app.use(credentials)
app.use(cors(corsOptions));
app.use(express.json());
app.use((bodyparser.urlencoded({ extended: true })));
app.use(cookieParser());
//CONNECTING TO DATABASE:
connection();
app.use('/user', userRouter);
//CONNECTION TO PORT:
app.listen(PORT, () => {
console.log(`This application is listening on port ${PORT}`);
});
Here userRouter.ts
import express, { Router } from 'express';
import { loginUserController, logoutUserController, protectedRouteController, refreshTokenController, registerUserController } from '../controllers/userController';
import passport from 'passport';
const userRouter: Router = express.Router();
userRouter.post('/register', registerUserController);
userRouter.post('/login', loginUserController);
userRouter.get('/refreshToken', refreshTokenController);
userRouter.post('/logout', logoutUserController);
//protected route
userRouter.get('/private', passport.authenticate('oidc'),protectedRouteController);
// keycloak.protect()
export default userRouter;
Request for guidance on properly configuring Passport.js. Could anyone share a template or step-by-step guide on how to set up Passport.js for keycloak effectively?

Apollo Server as Nuxt serverMiddleware

I've managed to have a express + Apollo Backend as a serverMiddleware in Nuxtjs.
Everything works fine(auth, cache, datasources, queries, mutations) but now I'm trying to get subscriptions(websockets) running and its giving me a hard time.
I tried this example https://www.apollographql.com/docs/apollo-server/data/subscriptions/#subscriptions-with-additional-middleware but even letting the httpServer listening didn't work.
This is my API file which I require through the nuxt.config.js with '~/api/index' :
module.exports = async () => {
const app = require('express')()
const server = await require("./apollo")() // apollo-server-express w/ typeDefs and resolvers
// apply Apollo to Express
server.applyMiddleware({ app });
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
return {
path: '/api',
handler: httpServer
}
}
Now my playground is giving me this error: "Could not connect to websocket endpoint ws://192.168.150.98:3000/api/graphql. Please check if the endpoint url is correct."
TypeDefs:
type Subscription {
postAdded: Post
}
type Post {
author: String
comment: String
}
type Query {
posts: [Post]
}
type Mutation {
addPost(author: String, comment: String): Post
}
Resolvers:
Query: {
posts(root, args, context) {
return Posts;
}
}
Mutation: {
addPost(root, args, context) {
pubsub.publish(POST_ADDED, { postAdded: args });
return Posts.add(args);
}
},
Subscription: {
postAdded: {
// Additional event labels can be passed to asyncIterator creation
subscribe: () => pubsub.asyncIterator([POST_ADDED]),
},
}
First question here, thank u in advance! :)
it can also be a little easier
1.
yarn add apollo-server-express
or
npm install apollo-server-express
create file ./server/index.js
import { ApolloServer, gql } from 'apollo-server-express'
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const server = new ApolloServer({ typeDefs, resolvers })
export default server
add in your nuxt.config.js
import server from './server'
export default {
// ... your nuxt config stuff
// ...
hooks: {
render: {
async before({
nuxt: {
server: { app },
},
}) {
await server.applyMiddleware({ app, path: '/api' })
console.log(`🚀 ApolloServer ready at /api`)
},
},
}
}
I found a hacky way to achieve it, import the code as a nuxt module:
import http from 'http'
export default function () {
this.nuxt.hook('render:before', async () => {
const server = require("./apollo")()
// apply Apollo to Express
server.applyMiddleware({ app: this.nuxt.renderer.app });
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
const httpServer = http.createServer(this.nuxt.renderer.app);
// apply SubscriptionHandlers to httpServer
server.installSubscriptionHandlers(httpServer);
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
// overwrite nuxt.server.listen()
this.nuxt.server.listen = (port, host) => new Promise(resolve => httpServer.listen(port || 3000, host || 'localhost', resolve))
// close this httpServer on 'close' event
this.nuxt.hook('close', () => new Promise(httpServer.close))
})
}
Tho I'm now using a probably more stable way, using nuxt programmatically!
With hapi instead of express, since express is giving me trouble compiling and not showing the loading-screen(progress of building).
Just use npx create-nuxt-app and create an app with a hapi server backend.
The code with hapi would look like this:
const consola = require('consola')
const Hapi = require('#hapi/hapi')
const HapiNuxt = require('#nuxtjs/hapi')
async function start () {
const server = require('./apollo/index')()
const app = new Hapi.Server({
host: process.env.HOST || '127.0.0.1',
port: process.env.PORT || 3000
})
await app.register({
plugin: HapiNuxt
})
app.route(await require('./routes')())
await server.applyMiddleware({
app,
path: '/graphql'
});
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
await server.installSubscriptionHandlers(app.listener)
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
await app.start()
consola.ready({
message: `Server running at: ${app.info.uri}`,
badge: true
})
}
process.on('unhandledRejection', error => consola.error(error))
start().catch(error => console.log(error))
Maybe i can help somebody
An easier way is to use the getMiddleware() method of Apollo Server Express:
Create a file under ./api/index.js:
const { ApolloServer, gql } = require('apollo-server-express')
const express = require('express')
const typeDefs = gql`
type Query {
hello: String
}
`
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(server.getMiddleware())
module.exports = app
and then register it in ./nuxt.config.js:
{
// other nuxt config ...
serverMiddleware: [{ path: '/api', handler: '~/api/index.js' }],
}

zeit-now v2 + apollo-server-express: playground error: Server cannot be reached

Currently I am trying to get an api for my nextjs project to work.
For deployment I am using zeit's NOW v2 (locally via "now dev").
Everything works fine except the graphql-server.
In playground and via client I get an 404-error.
Queries are getting executed correctly, but I get an error-object(query results are in the response-field; 404).
Checking it in the playground-gui: same problem and in the playground-input field showing the message "Server cannot be reached".
Playground Initial Error:
{
"error": "Response not successful: Received status code 404"
}
Playground after hello-query:
{
"error": {
"data": {
"hello": "Hello world!"
}
}
}
Browser-Console Playground:
Error: "Response not successful: Received status code 404"
This is my graphql-server loaded with now:
import express from 'express';
import { ApolloServer, gql } from 'apollo-server-express';
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({ typeDefs, resolvers,
introspection: true, playground: true,
subscriptions: {path: '/api'},
});
const app = express();
server.applyMiddleware({ app, path: "/api", cors: true });
module.exports = app;
Also tried this example. Same problem.
Can anyone tell me how to get it running properly?
I had a similar issue (server can't be reached). It was an authorization problem. The GraphQL Playground docs mention the request.credentials setting:
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: {
settings: {
// So that auth works
// Docs: https://github.com/prisma/graphql-playground
['request.credentials']: 'same-origin',
},
},
subscriptions: {path: '/api'}
});

REST API router forward to Apollo GraphQL endpoinr

I have a node/express/Apollo application to provide GraphQL service to the frontend application. I also have the REST API endpoing in the application to provide service for legacy applications. I want to forward the REST API calls to the GraphQL endpoint. For example:
From
GET /api/roles
to
POST /graphql
{ *body* }
I tried like this:
// app.js
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import routes from './routes';
const port = process.env.PORT || 8088;
const app = express();
app.use('/api/roles', routes.role);
const server = new ApolloServer({
......
},
});
server.applyMiddleware({ app, path: '/graphql' });
app.listen({ port: port }, () => {
console.log(`Apollo Server on http://localhost:${port}/graphql`);
});
// routes/role.js
import { Router } from 'express';
const router = Router();
router.get('/', (req, res, next) => {
req.url = '/graphql';
req.originalUrl = '/graphql';
req.method = 'POST';
req.body = `
{
findRoles {
data {
roleId
name
}
}
}`;
return router.handle(req, res, next);
});
It doesn't work and gives the error "Cannot POST /graphql". Any idea how to do it?

upgrading to apollo-server-express 2.0.0 context missing

Before the upgrade we were having
import express from 'express';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
const app = express();
app.use(
'/graphql',
bodyParser.json(),
graphqlExpress(req => ({
schema,
tracing: true,
context: { req },
})),
);
app.use(
'/graphiql',
graphiqlExpress({
endpointURL: '/graphql',
}),
);
In our resolvers we could get the req and set req.session.token as follows,
const customResover = {
Query: {
custom: async (root, args, context) => {
console.log(' resolver called with args', args);
const { req } = context;
... fetch token info and set
req.session.token = ${token};
...
but with the upgrade to version 2.0.0 the code is changed to following and I am not sure how to fix the CustomResolver, to set the session token, any idea how the above could be accomplished ?
import express from 'express';
import { ApolloServer, gql } from 'apollo-server-express';
import { typeDefs, resolvers } from './schema/';
const app = express();
const apollo = new ApolloServer({
typeDefs
resolvers,
engine: false
});
apollo.applyMiddleware({
app,
});
https://www.apollographql.com/docs/apollo-server/migration-two-dot.html#request-headers
const apollo = new ApolloServer({
typeDefs
resolvers,
context: ({ req }) => ({ req })
engine: false
});
Solves it but got an issue with Cookie with token not getting to the browser.