I'm making an API using NestJS (NodeJS) and in order to run it in local enviromment without having all external APIs running, i want to mock the calls to external APIs while my API running.
In order to do this, I choose Json-server to do it, Here is the code:
mockserver.ts:
export async function bootstrap() {
const app = create();
app.use(
defaults({
logger: true,
static: 'static',
}),
router(dbJSON),
jsonServer.rewriter(routesJSON),
);
app.use('/api', router);
}
i tried also :
export async function bootstrap() {
const app = create();
app.use(
defaults({
logger: true,
static: 'static',
}),
router(db),
jsonServer.rewriter(routesJSON),
);
app.use('/api', router);
const port = process.env.mockPort ?? 8080;
app.listen(port);
main.ts :
async function bootstrap() {
const app = await NestFactory.create(AppModule)
const mocks = await import('../mocks/server');
app.use(await mocks.bootstrap(null));
await app.listen(DEFAULT_HTTP_PORT, DEFAULT_HOST);
}
However, instead of mocking the calls to external APIs using the db and the routes given to Json-server, my API itself was mocked.
Any ideas on how can I mock an API calls to external API while running? or how to make json-server mock call httpService calls only instead of the API itself
I haven't tried this before, but I think you either need to configure the existing HttpModule to sometimes forward calls or wrap HttpModule with a new module that decides whether or not to forward requests to the real server or mock server.
You can give HttpModule a configuration via register. See the async configuration if you want to inject ConfigService to configure it based off of an environment variable that determines if you're local or not. The config object is an Axios request config. However, I don't see a way to redirect requests via config.
HttpModule uses axios, so another option would be axios interceptors. In a request interceptor, you could have it only override config.url when running locally. To set up interceptors at the beginning of the app, you could create a module MyHttpModule that injects HttpService, and in an onModuleInit, get a reference to the axios instance and set the interceptors. Check out this example I found.
Related
Running the exact same script in React is blocked by Cors policy, but not when I run it with node.
Why can it be done with node, but not with React?
How can I still fetch this in a React app?
It's also allowed in this chrome extension, is that because the script is executed visiting youtube so that domain is youtube?
async function isThisAllowed() {
const videoURL = `https://www.youtube.com/watch?v=QnQe0xW_JY4`
const data = await axios.get(videoURL);
console.log(data);
}
CORS is a way for websites (in this case YouTube) to prevent other domains from accessing them. Basically, in this case, scripts running on other domains will not be able to access youtube.com.
CORS is only enforced by browsers, so it makes sense that your Node script would work as expected while your React app wouldn't.
Here's a good explanation of how CORS works.
You could fix this with a simple Node proxy:
import express from "express";
import axios from "axios";
const app = express();
app.get("/proxy", async (req, res) => {
const resp = await axios.get(req.query.url);
res.send(resp.data);
});
app.listen(process.env.PORT || 3000);
Does NestJS support middleware with gRPC? I'm following the example project here and then the middleware for logging the request entrypoint here.
In the example project it looks like there is an Express server along with the gRPC server. I'm using just a gRPC server.
const app = await NestFactory.createMicroservice<MicroserviceOptions>(...);
await app.listenAsync();
So adding the following to the main app module:
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('*');
}
}
But nothing is logging.
Middleware is exclusive to HTTP handlers. If you need middleware-like functionality, it would be better to use one of Nest's enhancers (guards, interceptors, pipes, or filters). If you're looking to do some logging I'd suggest an intereptor as you have pre- and post- controller logic.
There's also my logging library Ogma which has a Nest package and interceptor already which might be useful to look at
I am trying to validate every HTTP request to the nuxt server for authorization.
In this official tutorial,
it requires me to add a validate function in every page, which seems not to work for me, as I'm seeking a way to write a middleware that validates all requests to the nuxt server.
And so, I found nuxt's middleware support, but the official document is really unfriendly, I can't understand at all.
What I'm expecting is a plugin-like module that allows me to put my middleware into nuxt.
Just like what can be achievable in Express (as following).
export default function (req, res, next)
So that I can easily validate headers per request to nuxt.
How can I achieve this? Thank you very much.
Go to your directory middleware/ and create an auth.js
The first argument is your context. Context contains alot of things like your store, app, route, redirect, and it also contains req
You can check out what context has in it: https://nuxtjs.org/api/context/
export default function ({ req, res, redirect }) {
let authenticated = false;
if(!authenticated) {
redirect("/login")
}
}
You can go now to on of your page, and add this to your export default {}
middleware: ["auth"]
Now if you try to access the page you should be redirected to login
I believe Nuxt Middleware is what you need.
In middleware/auth.js
// write any custom validation functions
export default function (context) {
context.userAgent = process.server
? context.req.headers['user-agent']
: navigator.userAgent
}
then in nuxt.config.js
// this will register the middleware functions above for every route
export default {
router: {
middleware: 'auth'
}
}
Ive been trying to deploy a Twitch like application using react, redux, node media server and json server module to Heroku. However, I keep running into a issue when trying to connect my react client and express server via a api request, during production.
Im trying to make the actual request through my action creators and by using axios with a base url of http://localhost:4000, however that only works on my local machine.
const response = await streams.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
You can view my full repo at https://github.com/XorinNebulas/Streamy
You can also view my current deployed version of the site on Heroku at
https://streamy-app.herokuapp.com/
here is my api/server.js file. My express server will be watching on a random port equal to process.env.PORT, so I have no way of knowing how to make a network request via my action creators to that random port during production.
const path = require("path");
const cors = require("cors");
const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults({
static: "../client/build"
});
const PORT = process.env.PORT || 4000;
// Set default middlewares (logger, static, cors and no-cache)
server.use(cors());
server.use(middlewares);
if (process.env.NODE_ENV === "production") {
// Add custom routes before JSON Server router
server.get("*", (req, res) => {
res.sendFile(
path.resolve(__dirname, "../", "client", "build", "index.html")
);
});
}
// Use default router
server.use(router);
server.listen(PORT, () => {
console.log(`JSON Server is listening on port ${PORT}`);
});
I expected the request to go thru and load up some data from api/db.json, with a resquest url of https://streamy-app.herokuapp.com/streams but instead i got a request url of http://localhost:4000/streams, which of course leads to the CORS issue below
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:4000/streams. (Reason: CORS request did not succeed).
I would truly appreciate any suggestions, been working on this for days.
Alright looks like I figured it out. I simply went into streams/client/package.json and added
"proxy":"http://localhost:4000"
I then went into streams\client\src and deleted the api folder which contained my custom axios with a base url. using instead axios out of the box for my action creators
const response = await axios.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
Now while running locally in development mode, I'm able to make a request to http://localhost:4000/streams, but after deploying my node app to Heroku I successfully make a request over to https://streamy-app.herokuapp.com/streams
hope this helps someone with slimier issues.
First, you should know that Heroku doesn't allow to expose multiple ports, which means you should change the approach of multiple ports to something else (see this answer).
Second, the file client/src/apis/streams.js is hard-coded configured to send requests to http://localhost:4000/ - which is not a good idea.
Whatever approach you choose - even deploying to another host server - you will need to dynamically configure the API endpoint, per environment.
I would also recommend you to:
Change the way you deploy react, as explained here.
After doing the above, consider consolidating your API service with the static server, so that you don't need multiple ports, and then everything becomes easier.
I am building React + Express app and I need to pass some config variables from server config into React App (for example API URL).
I need to do so in development (2 servers - Webpack Dev server + Node.js) and also in production (Only Node.js Express server with built frontend).
How to achieve this?
I tried to pass locals from Express to my template where I did window.config = '<%- JSON.stringify(config) %>' (EJS template system) and then used window.config in React App. I does not think this is right approach.
React is client side and no one will suggest you to pass your server config variables like api keys to client side but if you want to pass the config variables to client side.
You can make do it as
// import config variable to express app.js server side
const config = require('./config.js');
// send the config variable
app.get('/getconfig', (req, res) => {
res.json(config);
});
In the client side make axios get request to /getconfig in actions creator file
export function getConfig() {
const req = axios.get('/getconfig')
.then(res=> res.data)
.catch(err => console.log(err));
return {
type: "GETCONFIG",
payload: req
}
}
Now you can add it to reducers switch case and then use it in any react component.
You can consider to use DefinePlugin in webpack. This feature allow you to create global constants being used in the front-end logic. And as it is created at compile time, you can retrieve the config from Node layer.
For example, you have 2 GTM containers, one for development, another for production. And in the production webpack config, we can use some like this:
const config = require('./node/config/prod.js');
module.exports = {
// skip other setting...
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV' : JSON.stringify('production'),
'process.env.GTM_ID' : JSON.stringify(config.gtm.id)
});
]
};
Then in the html you can use process.env.GTM_ID to dynamically get the GTM id among the different environments.