Error: request entity too large in graphql services of node - node.js

I am working on node based graphql project, trying to send base64 format image to server.
I am using bodyparser module and configured it as bellow.
app.use(bodyparser.text({type: 'application/graphql'}));
app.use(bodyparser.json({limit: '50mb'}));
app.use(bodyparser.urlencoded({limit: '50mb', extended: true}));
I am able to send base64 images by direct node services but when it come to graphql services, it is throwing error as:
Error: request entity too large

For the sake of helping others who are using graphql-yoga npm package. The syntax to add bodyparser option is quite different and I took hours debugging & trying to make it work so adding the code here for reference :
const { GraphQLServer } = require("graphql-yoga");
const server = new GraphQLServer({
schema, //Your schema
context, //Your context
});
const options = {
port: 1234
bodyParserOptions: { limit: "10mb", type: "application/json" },
};
server.start(options, () =>
console.log(
"Server is running\m/"
)
);

Are you using the graphql-express npm package?
If so then the issue is likely this line:
https://github.com/graphql/express-graphql/blob/master/src/parseBody.js#L112
As you can see this sets a max size of 100kb for the request.
We ran into the same issue and fixed it by forking the repository and manually increased the max request size.
This might be a nice opportunity to contribute to the package though!
It would be nice if the limit were configurable.

For me, I specified the uploads and it worked:
const options = {
uploads: {
maxFieldSize: 1000000000,
maxFileSize: 1000000000
}
}
bodyParser only works with req.body and in your case you're handling multipart form

Related

Cannot get query param in nodejs

I have this proxy-middleware application. It is not including express.js.
Server.js contains this:
const app = require('connect')(),
http = require('http'),
While the middlewares a set of rules, for example:
const httpProxy = require('http-proxy'),
HttpProxyRules = require('http-proxy-rules'),
const proxyRules = new HttpProxyRules({
rules: {
'/api/v1/stuff/([0-9]+)/documents/': 'http://0.0.0.0:3000/$1',
},
default: 'http://localhost:4443'
});
So all the other microservices are being intercepted by this proxy.
There is an "app.use" where a few checks are made.
Here I can see the request-object. Im interested in reading the query parameter attached to the url.
So when I have this:
http://localhost:8081/api/v1.1/stuff/63/documents/file.pdf?token=mytoken
Printing this:
console.log('GATEWAY',req.originalUrl);
Will output this:
http://localhost:8081/api/v1.1/stuff/63/documents/file.pdf?token=mytoken
However, how can I access the query parameter? As Im not using express, doing "req.query" gives undefined.
I have tried a bunch of solutions: "querystring", "url" etc. But they give very strange result and it is not easy to get the field itself. I can never do something like:
req.query
I had a look at connect documentation but there is nothing about getting the request query parameters.
What should I use?
Please check if you used the followings:
If not, please add them:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
And try to get req.params

How to set the appropriate http headers for gzip

I'm using Unity's WebGL and I'm getting this message on the console "You can reduce your startup time if you configure your web server to host .unityweb files using gzip compression." So according to Unity's documentation, I need to add the correct response Headers https://docs.unity3d.com/Manual/webgl-deploying.html.
I found the "express-static-gzip" module, and I tried to do just that, but the warning is still there. Below is the server.
const express = require('express');
const ip = require("ip");
const expressStaticGzip = require('express-static-gzip');
const http = require('http');
const app = express();
const server = http.Server(app);
app.use('/public/Builds/Build/', expressStaticGzip('public/Builds/Build/', {
customCompressions: [{
encodingName: "gzip",
fileExtension: "unityweb"
}]
}));
// app.use(compression());
app.use(express.static('public'));
server.listen(3000, function(){
console.log( ":: http://" + ip.address() + "/ ::" );
});
Any ideas?
Nick
Many thanks to #d_shiv for his help. I changed the code to the following, and the warning went away.
(you can change gzip with br if you're using brotli)
const express = require('express');
const ip = require("ip");
const http = require('http');
const app = express();
const server = http.Server(app);
app.use(express.static('public', {
setHeaders: function(res, path) {
if(path.endsWith(".unityweb")){
res.set("Content-Encoding", "gzip");
}
}
}));
server.listen(3000, function(){
console.log( ":: http://" + ip.address() + ":3000/ ::" );
});
express-static-gzip does not gzip the files on the fly before serving it. It assumes that you have the normal as well as gzipped versions of the file available on the specified directory. Check the Examples section of documentation here.
In this scenario, if the public/Builds/Build/Builds.wasm.framework.unityweb had to be transferred with gzip compression, you'd need to create a gzipped version by name of public/Builds/Build/Builds.wasm.framework.unityweb.gz. The middleware will automatically scan the folder for all such file pairs where original as well as gzipped versions are available. It will serve the gzipped version when request comes for original file, if the browser supports it.
The customCompressions array should also be skipped since that's enabled by default. The middleware would be registered, something like this:
app.use('/Builds/Build/', expressStaticGzip('public/Builds/Build/'));
Also note that public/ is removed from the middleware path (should be present in the expressStaticGzip path though). This is because your assets are being loaded from path https://{hostname}/Builds/Build/....
If you intend to compress the files on the fly and server it, take a look at compression module. The can be very costly operation for your server though, if possible do the gzipping during build time to create the equivalent .gz files, and continue to use express-static-gzip.

How can my client get application configuration from the server when using Webpack?

I'm adding Webpack to a Node/Express app that previously used RequireJS. When the client needed some configuration from the server, we previously used a custom Express route that retrieved specific configs as JSON:
server/index.js - Set up Express routes for config files
const app = express();
const configRouter = express.Router();
configRouter.get('/some-config.json', (req, res) => {
const someConfig = {
prop1: getProp1(),
prop2: getProp2()
}
res.json(someConfig);
}
app.use('/config', configRouter);
client/controller.js - Use/config/some-config.json during initialization
define(['text!/config/some-config.json'], function(SomeConfig) {
// do something with SomeConfig
});
But removing RequireJS means I can no longer retrieve the JSON this way as a dependency. And it's not static JSON either, so it's not as simple as just placing it alongside client code and importing it.
So what is the best way to do this with Webpack? Any help greatly appreciated. Thanks!

How to increase default maximum request body size in loopback 4 framework?

How to increase default maximum request body size in loopback 4 framework?
I understand express is used internally by loopback 4, what I need to do is the equivalent of setting the limit param for the body-parser expressjs middleware.
Any ideas?
Thanks
server.bind(RestBindings.REQUEST_BODY_PARSER_OPTIONS).to({
limit: '4MB',
});
or
server.bind(RestBindings.REQUEST_BODY_PARSER_OPTIONS).to({
json: {limit: '4MB'},
text: {limit: '1MB'},
});
The list of options can be found in the body-parser module.
By default, the limit is 1MB. Any request with a body length exceeding the limit will be rejected with http status code 413 (request entity too large).
I updated index.ts to add rest request body parser configuration to the application options variable:
Increase limit to 6MB shown below:
import {ApiServerApplication} from './application';
import {ApplicationConfig} from '#loopback/core';
export {ApiServerApplication};
export async function main(options: ApplicationConfig = {}) {
options.rest = {requestBodyParser: {json: {limit: '6MB'}}};
const app = new ApiServerApplication(options);
await app.boot();
await app.start();
const url = app.restServer.url;
console.log(`Server is running at ${url}`);
return app;
}

Getting rid of session and socket pooling sailsjs

Hi I am current working on my rest api app using sails. I was reading the following article
http://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile
In point 2 it was suggested to get rid of socket pooling
var http = require('http');
var options = {.....};
options.agent = false;
var req = http.request(options)
and in point 7 it suggest to get rid of session by removing.
app.use(express.session({ secret: "keyboard cat" }));
I am wondering how I can do that in sails.
For Sails v0.11x, you should use the recommended approach of editing .sailsrc file, and setting:
{
"hooks": {
"session": false,
// also useful when building an API
"grunt": false,
}
}
In Sails.js v0.10 you can disable the session by adding the following key to your config/express.js file:
middleware: {
session: null
}
As far as socket pooling goes, I think they're talking about making http requests from the server, and just suggesting that when making such requests, you set the agent option to false.

Resources