How do I prevent response to be logged from specific route in Hapi.js using good? - hapi.js

I'm using good-squeeze the following way
// ...
{
module: 'good-squeeze',
name: 'Squeeze',
args: [
{
log: '*',
response: '*',
request: '*'
}
]
},
// ...
When I access localhost:3000/health it logs
2016-09-28T10:50:26.652, [response] http://0.0.0.0:3000: post /health {} 200 (321ms)
How do I prevent response logging from this specific route?

It seems that it's not possible to do it using good-squeeze so I've created my own good plugin which will exclude log when it's related to /health route.
const Stream = require('stream');
class ExcludePath extends Stream.Transform {
constructor() {
super({ objectMode: true });
}
_transform(data, enc, next) {
if (data.route === '/health') {
return next();
}
return next(null, data);
}
}
module.exports = ExcludePath;

Related

Nuxt Auth login - working on localhost, 301 and 405 on server

My problem is, that login/logout works perfectly on my localhost, but as soon as I deploy it on a server I got 301 and 405 errors, with the "The GET method is not supported for this route. Supported methods: POST" message and I cant figure it out why is that.
My nuxt.config.js:
},
auth: {
strategies: {
local: {
user: {
property: 'data'
},
token: {
maxAge: 86400,
global: true
},
endpoints: {
login: { url: '/api/auth/login/', method: 'post' },
logout: { url: '/api/auth/logout/', method: 'post' },
user: { url: '/api/auth/user/', method: 'get' }
}
},
}
},
build: {
My login method:
async login() {
this.errors = {};
try {
await this.$auth.loginWith('local', { data: this.loginForm });
...
} catch (error) {
if (error.response.status === 401) {
this.inactive = error.response.data.message;
}
this.errors = error?.response?.data?.errors;
}
},
My Laravel api.php:
Route::group(['prefix' => 'auth'], function () {
Route::post('login/', [AuthController::class, 'login']);
Route::post('register', [AuthController::class, 'register']);
Route::post('set-password', [AuthController::class, 'setPassword']);
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::get('user/', [AuthController::class, 'user']);
Route::post('logout/', [AuthController::class, 'logout']);
Route::post('password-reset', [AuthController::class, 'passwordReset']);
});
});
And i will attach my network tab from my browser (first is on localhost/working, second one is on a server/not working):
I don't know what I'm messing up but after several days of debugging I'm hopeless. I've emptied every possible caches on the backend side so I'm thinking thats not the problem. But hopefully somebody else will be much more clever than me and can tell me what's going on.

Hapi js validateFunc session param got null in some requests if i add keepAlive: true or update ttl in onPreResponse Middleware

i upgrade hapi from version 16.1.0 to 20.2.1, and i had to replace catbox-redis package with #hapi/catbox-redis and hapi-auth-cookie package with #hapi/cookie (by using documentation https://hapi.dev/tutorials/auth/?lang=en_US#cookie)
also i remove the depricated hapi-acl-auth package and use the new hapi js feature scope to define roles access routes https://github.com/hapijs/hapi/blob/master/API.md#route.options.auth.access.scope
if the user stills browse on the website, i wanna update TTL option (cookie time to live) by using keepAlive: true option or by using the following middleware onPreResponse by using cookiesAuth option:
server.ext('onPreResponse', function (request, h) {
if (request.auth.isAuthenticated && request.path !== '/logout') {
request.cookieAuth.ttl(TTL);
}
return h.continue;
});
if i remove keepAlive: true, or the middleware, i can browse normaly in the website, but if i add them some of request redirect me to the '/login' page then to homepage
server.auth.strategy('session', 'cookie', {
cookie: {
name: 'cookie_name',
password: 'cookie_password',
ttl: TTL,
isSecure: true,
isHttpOnly: true,
},
redirectTo: '/login',
appendNext: true,
keepAlive: true,
validateFunc: async function (request, session) {
if(session && session.sid) {
try {
let cached = await cache.get(session.sid)
if (!cached || !cached.account) {
return { valid: false };
}
const user = await User.findByPk(cached.account.id, {
include: [
{ model: UserRole, as: 'Roles' },
{ model: EcRole, as: 'EcRoles' }
]
})
if (!user) {
console.log(`----------------------------------------------------------------------- ~ file: index.js ~ line 196 ~ redirect no user`)
return { valid: false }
}
user.scope = await getUserRole(user)
cached.account = user
return { valid: true, credentials: cached.account };
} catch (error) {
console.log(`----------------------------------------------------------------------- ~ file: index.js ~ line 204 ~ error`, error)
return { valid: false };
}
} else {
console.log(`----------------------------------------------------------------------- ~ file: index.js ~ line 210 ~ no session`)
return { valid: false }
}
}
});
by adding some console.log, i find that during the execution of some request, the param session of validateFunc got null value and i get the message 'invalide key'
and also it can be probleme of RedisCache timing during write & read data from cache between 2 requests

Apollo Server & 4xx status codes

Currently, my Apollo Server(running on HapiJS) returns HTTP 200 for every request, including failed ones.
I would like the GraphQL server to return HTTP 4xx for unsuccessful requests. The primary reason for it is that I want to set up monitoring for my ELB.
I know that Apollo Server has an engine platform, but I want to implement it using my current infrastructure.
Any ideas of how I could accomplish that? I tried to capture 'onPreResponse' event for my HapiJS server but I couldn't modify status code there.
After reading this answer. Here is a solution by modifying the hapijs plugin graphqlHapi of hapiApollo.ts file.
server.ts:
import { makeExecutableSchema } from 'apollo-server';
import { ApolloServer, gql } from 'apollo-server-hapi';
import Hapi from 'hapi';
import { graphqlHapi } from './hapiApollo';
const typeDefs = gql`
type Query {
_: String
}
`;
const resolvers = {
Query: {
_: () => {
throw new Error('some error');
},
},
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
const port = 3000;
async function StartServer() {
const app = new Hapi.Server({ port });
graphqlHapi.register(app, { path: '/graphql', graphqlOptions: { schema } });
app.ext('onPreResponse', (request: any, h: any) => {
const response = request.response;
if (!response.isBoom) {
return h.continue;
}
return h.response({ message: response.message }).code(400);
});
await app.start();
}
StartServer()
.then(() => {
console.log(`apollo server is listening on http://localhost:${port}/graphql`);
})
.catch((error) => console.log(error));
hapiApollo.ts:
import Boom from 'boom';
import { Server, Request, RouteOptions } from 'hapi';
import { GraphQLOptions, runHttpQuery, convertNodeHttpToRequest } from 'apollo-server-core';
import { ValueOrPromise } from 'apollo-server-types';
export interface IRegister {
(server: Server, options: any, next?: Function): void;
}
export interface IPlugin {
name: string;
version?: string;
register: IRegister;
}
export interface HapiOptionsFunction {
(request?: Request): ValueOrPromise<GraphQLOptions>;
}
export interface HapiPluginOptions {
path: string;
vhost?: string;
route?: RouteOptions;
graphqlOptions: GraphQLOptions | HapiOptionsFunction;
}
const graphqlHapi: IPlugin = {
name: 'graphql',
register: (server: Server, options: HapiPluginOptions, next?: Function) => {
if (!options || !options.graphqlOptions) {
throw new Error('Apollo Server requires options.');
}
server.route({
method: ['GET', 'POST'],
path: options.path || '/graphql',
vhost: options.vhost || undefined,
options: options.route || {},
handler: async (request, h) => {
try {
const { graphqlResponse, responseInit } = await runHttpQuery([request, h], {
method: request.method.toUpperCase(),
options: options.graphqlOptions,
query:
request.method === 'post'
? // TODO type payload as string or Record
(request.payload as any)
: request.query,
request: convertNodeHttpToRequest(request.raw.req),
});
// add our custom error handle logic
const graphqlResponseObj = JSON.parse(graphqlResponse);
if (graphqlResponseObj.errors && graphqlResponseObj.errors.length) {
throw new Error(graphqlResponseObj.errors[0].message);
}
const response = h.response(graphqlResponse);
Object.keys(responseInit.headers as any).forEach((key) =>
response.header(key, (responseInit.headers as any)[key]),
);
return response;
} catch (error) {
// handle our custom error
if (!error.name) {
throw Boom.badRequest(error.message);
}
if ('HttpQueryError' !== error.name) {
throw Boom.boomify(error);
}
if (true === error.isGraphQLError) {
const response = h.response(error.message);
response.code(error.statusCode);
response.type('application/json');
return response;
}
const err = new Boom(error.message, { statusCode: error.statusCode });
if (error.headers) {
Object.keys(error.headers).forEach((header) => {
err.output.headers[header] = error.headers[header];
});
}
// Boom hides the error when status code is 500
err.output.payload.message = error.message;
throw err;
}
},
});
if (next) {
next();
}
},
};
export { graphqlHapi };
Now, when the GraphQL resolver throws an error, the client-side will receive our custom response with Http status code 400 instead of 200 status code with GraphQL errors response.
General from the browser:
Request URL: http://localhost:3000/graphql
Request Method: POST
Status Code: 400 Bad Request
Remote Address: 127.0.0.1:3000
Referrer Policy: no-referrer-when-downgrade
The response body is: {"message":"some error"}

Catch error server response with #nuxtjs/auth

I'm trying to catch the error response for #nuxtjs/auth but it doesn't seem to return anything but undefined.
It refuses to login if I include the user so I want to know why it's returning undefined.
CONFIG:
auth: {
strategies: {
local: {
endpoints: {
login: {
url: 'http://127.0.0.1:80/api/login',
method: 'post',
propertyName: 'token'
},
logout: false,
user: {
url: 'http://127.0.0.1:80/api/me',
method: 'get',
propertyName: undefined
}
},
tokenRequired: true,
tokenType: 'bearer',
}
},
plugins: [
'#/plugins/auth.js'
]
},
PLUGIN:
export default function ({ app }) {
app.$auth.onError((error, name, endpoint) => {
console.error(name, error)
});
}
VIEW FUNCTION:
- both handleSuccess and handleFailure returns undefined.
login() {
this.toggleProcessing(0);
let payload = {
username: 'admin',
password: 'admin123'
}
let handleSuccess = response => {
console.log(response);
this.toggleProcessing(0);
}
let handleFailure = error => {
console.log(error);
this.toggleProcessing(0);
}
this.$auth.loginWith('local', { data: payload }).then(handleSuccess).catch(handleFailure);
},
You can use e.response
async login() {
try {
const login = {
username: this.username,
password: this.password
}
let response = await this.$auth.loginWith('local', { data: login })
console.log('response', response)
} catch (e) {
console.log('Error Response', e.response)
}
}
I fell into the same problem and after spending some time i found out a very good way to catch the response. The solution is to use the axios interceptor. Just replace your plugin file code with the following
export default function ({$axios, $auth}){
$axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
}
I'm not sure initially what might be wrong here because I can't see the complete nuxt.config.js and your full component but here are a few things to check:
#nuxtjs/axios is installed
Both axios and auth modules are registered in the modules section of nuxt.config.js:
modules: [
'#nuxtjs/axios',
'#nuxtjs/auth'
]
Also, ensure the middleware property for auth is set in the component/page component.
Ensure you're following the documentation on this page: https://auth.nuxtjs.org/getting-starterd/setup
Ive been using try -> this.$auth.loginWith to catch error server response with #nuxtjs/auth.
login() {
const data = { form };
try {
this.$auth
.loginWith("local", { data: data })
.then(api => {
// response
this.response.success = "Succes";
})
.catch(errors => {
this.response.error = "Wrong username/password";
});
} catch (e) {
this.response.error = e.message;
}
},
Specify the token field in the nuxt.config
strategies: {
local: {
endpoints: {
login: { // loginWith
url: "auth/login",
method: "post",
propertyName: "data.token" // token field
},
user: { // get user data
url: "auth/user",
method: "get",
propertyName: "data.user"
},
}
}
},
modules: ["#nuxtjs/axios", "#nuxtjs/auth"],

No error shown in console when thrown from inside hapi plugin

For some reason no error shows up in the server console when I start my hapi server with nodemon and navigate to http://localhost:3000/hapi-ext-fetch and this makes debugging very difficult. Here is my code:
var Hapi = require('hapi');
var Joi = require('joi');
var fetch = require('isomorphic-fetch');
var debugMode = { debug: { request: [ 'error', 'request-internal' ] }};
var server = new Hapi.Server(debugMode);
server.connection({ port: 3000 });
var myPlugin = {
register: function (server, options, next) {
server.route([
{
method: 'GET',
path: '/{name}',
handler: function ( request, reply ) {
throw new Error('this error isnt shown!');
},
config: {
validate: {
params: {
name: Joi.string().min(3).max(10)
}
}
}
}
]);
next();
}
};
myPlugin.register.attributes = {
name: 'myPlugin',
version: '1.0.0'
};
server.register([
{
register: myPlugin,
routes: {
prefix: '/test'
}
}
], function() {
server.ext( 'onPreResponse', ( request, reply ) => {
if ( typeof request.response.statusCode !== 'undefined' ) {
return reply.continue();
}
fetch('http://localhost:3000/test/whatever')
.then(function(result) {
reply(result);
})
.catch(function(err) {
reply('error on server side: ' + err.stack);
});
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
I'm using hapi 13.0.0
Can't say I totally understand your use case here and if this question will be helpful to other people. But what you're trying to do it seems is:
Send a request to /hapi-fetch-ext
Have that request 404
And then in an onPreResponse go fetch another route /test/whatever
Hope to see the "this error isn't shown error"
Not sure if you're aware but this is going to cause an infinite cycle of requests (your fetch will cause another onPreResponse and so on and so on). So you should probably only go fetch on a 404:
server.ext( 'onPreResponse', ( request, reply ) => {
if (request.response.isBoom && request.response.output.statusCode === 404) {
return fetch('http://localhost:3000/test/whatever')
.then(function(result) {
reply(result);
})
.catch(function(err) {
reply('error on server side: ' + err.stack);
});
}
return reply.continue();
});