Haste module 'nodemailer' does not exist in haste module map - react-native

Im building a mobile app from the beonews pro template. I needed to add in some email functionality for a contact form. So naturally I did npm install nodemailer only to see the following error.
Haste module 'nodemailer' does not exist in haste module map
It lists off the four steps to follow
1.watchman watch-del-all
2.rm -rf node_module && yarn
3.rm -rf /tmp/metro-bundler-cache-*
4.rm -rf /tmp/haste-map-react-native-packager-*
After following the above steps I still receive the same error.
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { View, Text, ScrollView, TextInput, Button, Image, Animated } from 'react-native'
import wp from '#services/WPAPI'
import WebView from '#components/WebView/WebView'
import AnimatedButton from '#components/AnimatedButton/index'
import { Toolbar } from '#components'
import styles from './styles'
import nodemailer from 'nodemailer';
export default class CustomPage extends PureComponent {
static propTypes = {
id: PropTypes.any,
}
constructor(props) {
super(props)
this.state = {
newsletterFName: '',
newsletterLName: '',
newsletterEmail: '',
contactFName: '',
contactLName: '',
contactEmail: '',
contactMessage: '',
loading: false,
success: false
}
}
onSubmitNewsletter() {
console.log('the form has been submitted');
this.setState({
loading: true
})
fetch('https://us18.api.mailchimp.com/3.0/lists/dad57ba7fe/members', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, *same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // no-referrer, *client
body: JSON.stringify({
"email_address": this.state.newsletterEmail,
"status": "subscribed",
"merge_fields": {
"FNAME": this.state.newsletterFName,
"LNAME": this.state.newsletterLName
}
}), // body data type must match "Content-Type" header
})
.then(response => {
console.log('response before timeout', response);
setTimeout(() => {
console.log('inside timout')
if(response.status !== 200) {
this.setState({
loading: false,
})
} else {
this.setState({
loading: false,
newsletterEmail: '',
newsletterFName: '',
newsletterLName: '',
success: true
})
}
}, 2000);
});
}
onSubmitContactForm() {
console.log('contact form submitted');
let email = this.state.contactEmail;
let first = this.state.contactFName;
let last = this.state.contactLName;
let msg = this.state.contactMessage;
// async..await is not allowed in global scope, must use a wrapper
async function main(){
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.office365.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'xxx', // generated ethereal user
pass: 'xxx' // generated ethereal password
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred foos" <foo#example.com>', // sender address
to: this.state.contactEmail, // list of receivers
subject: 'News.Law Mobile Contact Form', // Subject line
text: this.state.contactMessage, // plain text body
html: this.state.contactMessage // html body
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error);
}
}
I expect the package to load so I can send an email based of contact form submission. actual results gets me an error described above.

In this instance what worked for me was to make sure I restarted the computer after following the four steps. I think it may have had something to do with the simulator? But am unsure.

Related

Vue Apollo Upload file crashes Node Maximum call stack size exceeded at _openReadFs

I am trying to setup front end for graphQl file upload with Apollo-boost-upload. The backend code is based on this link
https://dev.to/dnature/handling-file-uploads-with-apollo-server-2-0-14n7.
It's now reaching the resolver breakpoint after adding the following line in the server.js file
const { apolloUploadExpress } = require("apollo-upload-server");
app.use(apolloUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
And after modifying the schema for the upload type
scalar Upload
Here is the Vue component
<input
type="file"
style="display:none"
ref="fileInput"
accept="image/*"
#change="upload"
>
//Upload method
upload({ target: { files = [] } }) {
if (!files.length) {
return;
}
this.logoImage = files[0];
},
//Dispatching action from vue component
this.$store.dispatch("uploadLogo", { image: this.logoImage });
//Vuex action
const uploadLogo = async (context, payload) => {
context.commit("setLoading", true);
try {
const { data } = await apolloClient.mutate({
mutation: UPLOAD_LOGO,
variables: {file: payload.image},
context: {
hasUpload: true,
},
});
context.commit("setLoading", false);
console.log("Logo:", data.uploadLogo);
} catch (error) {
context.commit("setLoading", false);
console.log(error);
}
};
//Mutation
export const UPLOAD_LOGO = gql`
mutation uploadLogo($file: Upload!) {
uploadLogo(file: $file) {
_id
path
filename
mimetype
user {
_id
}
}
}
`;
// Apolloclient config on main.js
import ApolloClient from "apollo-boost-upload";
import { InMemoryCache } from "apollo-boost";
import VueApollo from "vue-apollo";
// Set up Apollo Client
export const defaultClient = new ApolloClient({
uri: "http://localhost:4000/graphql",
cache: new InMemoryCache({
addTypename: false,
}),
fetchOptions: {
credentials: "include",
},
request: (operation) => {
// if no token in local storage, add it
if (!localStorage.someToken) {
localStorage.setItem("someToken", "");
}
// operation adds the token to authorizatrion header, which is sent o backend
operation.setContext({
headers: {
authorization: "Bearer " + localStorage.getItem("someToken"),
},
});
},
onError: ({ graphQLErrors, networkError }) => {
if (networkError) {
console.log("[networkError]", networkError);
}
if (graphQLErrors) {
for (const error of graphQLErrors) {
console.dir(error);
if (error.name === "AuthenticationError") {
// set auth errir in state
store.commit("setError", error);
// signout user to clear error
store.dispatch("signUserOut");
}
}
}
},
});
Here is the updated typedef (old code commented out) from backend if that helps to identify the issue
const logoUploadTypeDefs = gql`
type File {
_id: ID!
path: String!
filename: String!
mimetype: String!
encoding: String!
user: User
}
# input Upload {
# name: String!
# type: String!
# size: Int!
# path: String!
# }
scalar Upload
type Mutation {
uploadLogo(file: Upload!): File
}
type Query {
info: String
logo: File!
}
`;
Now, the Node app crashes with the following log
I had to change "apollo-upload-server" to "graphql-upload"
change 1:
Commented out "apollo-upload-server" and used "graphql-upload"
// const { apolloUploadExpress } = require("apollo-upload-server");]
const {
graphqlUploadExpress, // A Koa implementation is also exported.
} = require("graphql-upload");
And in the middleware, used this
change 2:
app.use(graphqlUploadExpress());
await apolloServer.start();
instead of old code
app.use(apolloUploadExpress());// Not to be used
await apolloServer.start();
Also, in the resolver, I added this
change 3:
Import Upload from graphql-upload in the resolver file
const { GraphQLUpload } = require("graphql-upload");
....
....
const resolvers = {
// This maps the `Upload` scalar to the implementation provided
// by the `graphql-upload` package.
Upload: GraphQLUpload,
Query: {
....
}
Mutations: {
....
}
}
Refer to Apollo Docs for more details. This fixed the issue of Node crashing with error "Maximum call stack size exceeded at _openReadFs..."

Send silent request to refresh tokens

I am using Vue.js in frontend and JWT based authentication system. I have refresh tokens and access tokens. Access tokens have short amount of expiration time whereas refresh tokens have way longer. I want to send a request to server to refresh user's access token silently. I know when the access token will be expired. I want to refresh it 1 minute, or something, before it expires. How can I implement this? I thought to do it with putting a counter to my root component but I have no an exact solution. Thanks.
I have a similar problem as you do and found this Vue JWT Auth in the same search that pulled your answer. Implementation was a little more challenging than I had originally anticipated.
My application needs to have the JWT tokens refresh on page reloads and immediately before API calls. To do this I use axios to consume the APIs, allowing the use of an interceptor to check the validity of the tokens. To keep the UX smooth, I use the vuex store to maintain the tokens, escalating to localStorage, and then to making an external request for new tokens if each previous stage was not successful.
The components outside of the store look like:
src/utils/apiAxios.js: used to consume APIs
import axios from 'axios'
import config from '../../config'
import store from '../store'
const apiAxios = axios.create({
baseURL: `${config.dev.apiURL}api/`,
timeout: 1000,
headers: {'Content-Type': 'application/json'}
})
// before any API call make sure that the access token is good
apiAxios.interceptors.request.use(function () {
store.dispatch('isLoggedIn')
})
export default apiAxios
To src/main.js added these lines:
import store from './store'
router.beforeEach((to, from, next) => {
let publicPages = ['/auth/login/', '/auth/register/']
let authRequired = !publicPages.includes(to.path)
let loggedIn = store.dispatch('isLoggedIn')
if (authRequired && !loggedIn) {
return next('/auth/login/')
}
next()
})
src/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'
import auth from './modules/auth'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
modules: {
auth
},
strict: debug,
plugins: debug ? [createLogger()] : []
})
src/store/modules/auth.js:
import axios from 'axios'
import jwtDecode from 'jwt-decode'
import router from '../../utils/router'
import apiAxios from '../../utils/apiAxios'
import config from '../../../config'
export default {
state: {
authStatus: '',
jwt: {
refresh: '',
access: ''
},
endpoints: {
obtainJWT: config.dev.apiURL + 'auth/',
refreshJWT: config.dev.apiURL + 'auth/refresh/',
registerJWT: config.dev.apiURL + 'auth/register/',
revokeJWT: config.dev.apiURL + 'auth/revoke/',
verifyJWT: config.dev.apiURL + 'auth/verify/'
}
},
mutations: {
UPDATE_TOKEN (state, newToken) {
apiAxios.defaults.headers.common['Authorization'] = `Bearer ${newToken.access}`
localStorage.setItem('jwtAccess', newToken.access)
localStorage.setItem('jwtRefresh', newToken.refresh)
state.authStatus = 'success'
state.jwt = newToken
},
UPDATE_STATUS (state, statusUpdate) {
state.authStatus = statusUpdate
},
REVOKE_TOKEN (state) {
delete apiAxios.defaults.headers.common['Authorization']
localStorage.removeItem('jwtAccess')
localStorage.removeItem('jwtRefresh')
state.authStatus = ''
state.jwt = {
refresh: '',
access: ''
}
}
},
getters: {
authStatus: state => state.authStatus,
isLoggedIn: getters => {
// quick check of the state
return getters.authStatus === 'success'
}
},
actions: {
login ({ state, commit }, { email, password }) {
axios({
url: state.endpoints.obtainJWT,
method: 'POST',
data: {
email: email,
password: password
},
headers: {'Content-Type': 'application/json'}
})
.then((response) => {
commit('UPDATE_TOKEN', response.data)
})
.catch((error) => {
commit('UPDATE_STATUS', error)
console.log(error)
})
},
register ({ state, commit }, { email, password, firstName, lastName }) {
axios({
url: state.endpoints.registerJWT,
method: 'POST',
data: {
email: email,
password: password,
first_name: firstName,
last_name: lastName
},
headers: {'Content-Type': 'application/json'}
})
.then((response) => {
commit('UPDATE_TOKEN', response.data)
})
.catch((error) => {
commit('UPDATE_STATUS', error)
console.log(error)
})
},
logout ({ state, commit }) {
let refresh = localStorage.getItem('jwtRefresh')
axios({
url: state.endpoints.revokeJWT,
method: 'POST',
data: { token: refresh },
headers: {'Content-Type': 'application/json'}
})
.then(commit('REVOKE_TOKEN'))
.catch((error) => {
commit('UPDATE_STATUS', error)
console.log(error)
})
},
refreshTokens ({ state, commit }) {
let refresh = localStorage.getItem('jwtRefresh')
axios({
url: state.endpoints.refreshJWT,
method: 'POST',
data: {refresh: refresh},
headers: {'Content-Type': 'application/json'}
})
.then((response) => {
this.commit('UPDATE_TOKEN', response.data)
})
.catch((error) => {
commit('UPDATE_STATUS', error)
console.log(error)
})
},
verifyToken ({ state, commit, dispatch, getters }) {
let refresh = localStorage.getItem('jwtRefresh')
if (refresh) {
axios({
url: state.endpoints.verifyJWT,
method: 'POST',
data: {token: refresh},
headers: {'Content-Type': 'application/json'}
})
.then(() => {
// restore vuex state if it was lost due to a page reload
if (getters.authStatus !== 'success') {
dispatch('refreshTokens')
}
})
.catch((error) => {
commit('UPDATE_STATUS', error)
console.log(error)
})
return true
} else {
// if the token is not valid remove the local data and prompt user to login
commit('REVOKE_TOKEN')
router.push('/auth/login/')
return false
}
},
checkAccessTokenExpiry ({ state, getters, dispatch }) {
// inspect the store access token's expiration
if (getters.isLoggedIn) {
let access = jwtDecode(state.jwt.access)
let nowInSecs = Date.now() / 1000
let isExpiring = (access.exp - nowInSecs) < 30
// if the access token is about to expire
if (isExpiring) {
dispatch('refreshTokens')
}
}
},
refreshAccessToken ({ dispatch }) {
/*
* Check to see if the server thinks the refresh token is valid.
* This method assumes that the page has been refreshed and uses the
* #verifyToken method to reset the vuex state.
*/
if (dispatch('verifyToken')) {
dispatch('checkAccessTokenExpiry')
}
},
isLoggedIn ({ getters, dispatch }) {
/*
* This method reports if the user has active and valid credentials
* It first checks to see if there is a refresh token in local storage
* To minimize calls it checks the store to see if the access token is
* still valid and will refresh it otherwise.
*
* #isLoggedIn is used by the axios interceptor and the router to
* ensure that the tokens in the vuex store and the axios Authentication
* header are valid for page reloads (router) and api calls (interceptor).
*/
let refresh = localStorage.getItem('jwtRefresh')
if (refresh) {
if (getters.isLoggedIn) {
dispatch('checkAccessTokenExpiry')
} else {
dispatch('refreshAccessToken')
}
return getters.isLoggedIn
}
return false
}
}
}
I'm using django for my backend and django-rest-framework-simplejwt for the tokens. The returned JSON is formatted like:
{
access: "[JWT string]",
refresh: "[JWT string]"
}
with a token structure of:
header:
{
"typ": "JWT",
"alg": "HS256"
}
payload:
{
"token_type": "access",
"exp": 1587138279,
"jti": "274eb43bc0da429a825aa30a3fc23672",
"user_id": 1
}
When accessing the refresh endpoint, SimpleJWT requires in the data the refresh token be named refresh; for the verification and the revocation (blacklisting) endpoints the refresh token needs to be named token. Depending on what you are using for your backend will require modification from what I did.
The access token is only used in the api Authentication header and is updated when the mutations are called.
To get the token so I could decode it I used a simple shell script:
#!/usr/bin/env bash
EMAIL="my#email.com"
PASSWORD="aReallyBadPassword"
echo "API Login Token"
JSON_FMT='{"email":"%s","password":"%s"}'
JSON_FMT=` printf "$JSON_FMT" "$EMAIL" "$PASSWORD" `
curl \
--request POST \
--header Content-Type:application/json \
--data $JSON_FMT \
http://localhost:8000/api/auth/
echo ""

Angular Login issue

I am new in Angular 7. I am working in a Angular 7 project. I have a login component like below
import { Component, OnInit } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { TokenService } from '../../token.service'
import { Router, ActivatedRoute } from '#angular/router';
import { ServerService } from 'src/app/server.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
response: any;
failmsg: boolean = false;
constructor(private http: HttpClient,
private server: ServerService,
private Token: TokenService,
private router: Router,
private _router: ActivatedRoute
) { }
public form = {
grant_type: 'password',
client_id: 2,
client_secret: 'W5nQYuW1OFknDwiDnU96Y7dBMqTJ5jG6r6AXYk9q',
username: null,
password: null
}
headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
login() {
this.http.post(this.server.base_url + "login", this.form).subscribe( //execution is not entering inside this block
(data) => {
this.handleResponse(data);
this.http.get(this.server.base_url + "employees/employee/user/profile", { headers: this.headers }).subscribe(
(profile) => {
this.employeeProfile = profile;
if (this.employeeProfile.user_id == 1) {
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/dashboard'])
.then(rel => location.reload());
} else {
localStorage.setItem('employeeId', this.employeeProfile.employeeId);
localStorage.setItem('id', this.employeeProfile.id);
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/employee-dashboard'])
.then(rel => location.reload());
}
}
)
},
(error) => { //execution is entering inside this block
console.log('hello');
if (error) {
this.failmsg = true;
}
console.log(error);
}
);
}
employeeProfile: any;
handleResponse(data) {
this.Token.set(data.access_token);
this.headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
}
onClose() {}
handleResponse2() {
return this.Token.get();
}
ngOnInit() {
localStorage.setItem('portal', this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url(this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url2(this._router.snapshot.paramMap.get("portal"));
}
}
I can't login. I am getting error like below
My network tab is like below
Could anyone help me to fix this issue ?
Your target in proxy.conf should be http://alasr.com not localhost:4200.
What happen is --proxy-config option will treat http://alasr.com as though it is running on the same port as ur angular which is localhost:4200. So there will be no Cross Origin problem.
Btw, u can use npm 'start' script to give the proxy.conf file to the --proxy-config option
You are not able to hit the backend endpoints because of CORS- Cross origin resource sharing issue. You can check this link for more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
To fix this issue in angular you need to use --proxy-config option with your ng serve command. First, you need to create a JSON file proxy.conf.json and add below content:
{
"/al-asr": {
"target": "http://alasr.com",
"secure": false
}
}
I am assuming, Your backend is running in url http://alasr.com and url base is /al-asr.
Also in your httpClient pass the url like this
this.http.get('/al-asar/api/in/v1/employees/employee/user/profile')
Now run the server with below command to fix this issue:
ng serve --proxy-config proxy.conf.json
Try this
{
"/api": {
"target": "https://9c8c4aa0.ngrok.io",
"secure": true,
"changeOrigin": true,
"logLevel": "debug"
}
}

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"],

I can't seem to find my headers in the response from my express back-end in nativescript angular response

I can't seem to find any headers in the response from my express back-end in nativescript angular response,i previously had res.header but wasn't any different.
Express back-end :
router.post('/login', (req, res) => {
User.findOne({
email: req.body.email
})
.then((foundUser) => {
if (!foundUser) res.send('Email Or Password Is Invalid');
else {
bcrypt.compare(req.body.password, foundUser.password) //compare hashed with db string
.then((validPassword) => {
if (!validPassword) res.send('Invalid Email Or Password').status(400);
else {
const token = jwt.sign({
_userID: foundUser.userID
}, config.get('jwtPrivateKey'));
res.set({
'content-type': 'application/json',
'x-auth-token': token
}).send('Logged In').status(200);
}
});
}
}).catch((err) => {
res.send('Oops something went wrong').status(500);
});
});
Nativescript Http:
onLogin(){
console.log(this.textScrap());
this.registartion.Login(this.textScrap())
.subscribe((response) => {
console.log(response);
},(err) => {
console.log(err);
},() => {
// this.router.navigateByUrl() Navigate to homePage when ready
})
}
Then I end up with this response but no header included
{
JS: "headers": {
JS: "normalizedNames": {},
JS: "lazyUpdate": null,
JS: "headers": {}
JS: },
JS: "status": 200,
JS: "statusText": "Unknown Error",
JS: "url": null,
JS: "ok": false,
JS: "name": "HttpErrorResponse",
JS: "message": "Http failure during parsing for (unknown url)",
JS: "error": {}
JS: }
I had a similar issue in NativeScript using Angular6 (and 7), and it turned out to be the Angular HttpClient rejecting empty responses with a status code of 200 instead of 204 (no content). The log showed the same message that you receive.
Even though your server code seems to send a non-empty response on successful logins ('Logged in'), you can try to add an Interceptor in your Angular appplication
to inspect the error further.
In my case I added an Interceptor which sets the body to null in case the HttpClient encounters an error and the status code indicates a successful response:
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpResponse,
HttpEvent,
HttpErrorResponse
} from '#angular/common/http';
#Injectable()
export class EmptyResponseBodyErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler): Observable> {
return next.handle(req).pipe(
catchError((err: HttpErrorResponse, caught: Observable>) => {
if (err.status >= 200 && err.status &lt 300) {
const res = new HttpResponse({
body: null,
headers: err.headers,
status: err.status,
statusText: err.statusText,
url: err.url
});
return of(res);
}
throw err;
}
));
}
}
Add it to providers in your app.module.ts:
{ provide: HTTP_INTERCEPTORS, useClass: EmptyResponseBodyErrorInterceptor, multi: true },
I did not experience the same issue when running this in Chrome, Firefox or Safari, though - only in NativeScript (both Android and iOS).