Express GraphQL TTFB is extremely long - express

I have a very simple setup. Express-GraphQL API with MongoDB database. MongoDB responses are in general quite fast but when I would like to return from GrapQL API, TTFB is taking too long especially for multi-user queries.
For example, when I request a user, TTFB is 25.65 ms and content download is around 0.6 ms. But when I request all users with same fields TTFB is 4.32s and content download is around 1.28s.
Content download is no problem but I feel like TTFB is longer than it should be. You can check part of my Schema with RootQuery below.
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: {mail: {type: GraphQLString}},
resolve(parent, args){
return User.findOne({mail: args.mail});
}
},
users: {
type: new GraphQLList(UserType),
resolve(parent,args){
return User.find({}).collation({ locale: "en" }).sort({name: 1, surname: 1});
}
}
}
});
What would be the best way to decrease TTFB?

From your code snippet I can't see how the UserType is defined and I don't know also how the graphql query you are performing is exactly. Having said that, high TTFB numbers usually indicate that the server is performing heavy tasks, so, is very likely you are requesting a field from UserType in the query that has an expensive resolver associated (performing another MongoDB query maybe) which will be executed as many times as users exist. This is known as the N+1 problem and you could get rid of it using a dataloder, which will allow you to batch those expensive MongoDB queries in one query.
If you could give more information about the UserType and the query you are performing it would help a lot.
References:
- https://itnext.io/what-is-the-n-1-problem-in-graphql-dd4921cb3c1a
- https://github.com/graphql/dataloader

Related

How to configure Prebid server-side (s2sConfig) to pass keywords to the auction server

Documentation is limited. However, I seek to understand the s2sConfig that will send keywords to the auction server, similar to the prebid.js (pbjs.setConfig) approach - see below:
pbjs.setConfig({
appnexusAuctionKeywords: {
genre: ['classical', 'jazz'],
instrument: 'piano'
}
});

Apollo server is very slow even with light queries

I know that GraphQL can get slower with large data sets, but what I have is an array of around 60 items. E.g. in a simple query, I fetch, the id, title and country and it takes more than 3 ms on average for the Apollo server to return data while the resolver reruns data calling a REST endpoint in less than 200ms. I use Apollo studio to debug queries and what I get does not help me at all - everywhere less than 1 ms.
If I go for a more complex query with 2 nested queries, it take 15-20 seconds for the same 60 items and the nested queries are quite light.
I googled and found that people face similar issues with really heavy queries with thousands of items and they talk about a few seconds, not 15-20 seconds.
Feels like there is something wrong in my setup. I do not get any errors.
I am using apollo-server-express with a basic setup:
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: !(process.env.NODE_ENV === 'production'),
engine: {
reportSchema: true,
graphVariant: 'current',
},
subscriptions: {
onConnect: () => winston.info('Connected to websocket'),
onDisconnect: webSocket => winston.info(`Disconnected from websocket ${webSocket}`),
},
context: ({ req }) => ({
//eslint-disable-line
req,
pubSub,
}),
});

How to get AWS API Gateway to validate JSON Body against Model

The newly released "x-amazon-apigateway-request-validator" (in April I believe) is supposed to be able to run a JSON schema validation against the POST/PUT payload of an API.
I've tried to implement this in several different ways now but I can't make it work...
I have added the validators:
"x-amazon-apigateway-request-validators": {
"ValidateBody": {
"validateRequestParameters": false,
"validateRequestBody": true
},
"ValidateHeaders": {
"validateRequestParameters": true,
"validateRequestBody": false
}
}
For any methind I will look for specific headers so I also have the parameters in the "root" of the Swagger:
"x-amazon-apigateway-request-validator": "ValidateHeaders"
In the POST I have a x-amazon-apigateway-request-validator: ValidateBody and then a Model with the JSON schema where several elements are required.
I can however POST anything as long as it is JSON... There is no validation against the JSON schema done...
What am I missing?
It is working!
There is a time lag between the deploy and the actual usage of the new code even though I am not doing any caching it seems.
Went out for lunch and came back to a working solution!
{
"message": "Invalid request body"
}
It would be nice to be able to modify the response message though...

Accessing current user on ExpressJs - Passport

I'm creating a backend app using expressJs and passportjs (local strategy) to secure some of the routes.
I need to add the information for the current user on every Database query so we only expose the relevant information to each user.
I know you can access the information for current user checking req.user, but that will involve passing the user information (or even the request) as a parameter through all my call-stack, and I found it a bit inconvenient.
Is there to get the user information on the last layer (the one preparing the sql statement) without adding it on the parameters?.
Thanks.
Why not get the user information on the last layer by id ? Since you are using passport-local, you can query a user by id in the last database query by accessing req.user.id . No parameter is needed.
router.post('/your/route', function(req, res) {
User.findOne({
where: {id: req.user.id}
}).then(function(user) {
// do something
});
//send response
});
You can pass to passport's done function as the second parameter the user object with your custom data, like this:
done(null, {id: 1, name: 'John'});
and the req.user will return {id: 1, name: 'John'}

Current MongoDB server time in VB.Net

How do I get the MongoDB's time or use it in a query from VB.NET?
For example, in the Mongo shell I would do:
db.Cookies.find({ expireOn: { $lt: new Date() } });
In PHP I can easily do something like this:
$model->expireOn = new MongoDate();
How do I approach this in VB.Net? I don't want to use the local machine's time. This obviously doesn't work...
MongoDB.Driver.Builders.Query.LT("expireOn", "new Date()")
If you merely want to remove expired cookies from your collection, you could use the TTL collection feature which will automatically remove expired entries using a background worker on the server, hence using the server's time:
db.Cookies.ensureIndex( { "expireOn": 1 }, { expireAfterSeconds: 0 } )
If you really need to query, use a service program that runs on the server or ensure your clocks are reasonably synchronized because clocks that are considerably off can cause a plethora of problems, especially for web servers and email servers. (Consider HTTP headers like Date, LastModified and If-Modified-Since, Email Timestamps, HMAC/timestamp validation against replay attacks, etc.).