How to differentiate between a resolver call from federation and from client? - node.js

I am working in a GraphQL project using node + typegraphql + apollo-server.
My goal is to have specific metrics for regular queries, and separately, from federations. Is it possible to differentiate it in the server that is being requested and resolves the data?
By regular query I mean:
Client asks for User -> Apollo Gateway Server -> User Apollo Server resolves the User
And by a federated one I mean:
Client asks for Profile (which contains external User) -> Apollo Gateway Server -> User Apollo Server resolves the User
Apparently, this is possible using the DGS framework, #DgsQuery is for regular resolvers and #DgsEntityFetcher(name = "User") would work for the federation resolver.
The project related dependencies are:
"dependencies": {
"#apollo/federation": "^0.30.0",
"apollo-datasource-rest": "^3.1.1",
"apollo-graphql": "^0.9.3",
"apollo-server": "^3.1.2",
"apollo-server-express": "^3.1.2",
"graphql": "^15.5.1",
"graphql-tag": "^2.12.5",
"graphql-tools": "^8.1.0",
"type-graphql": "^1.1.1"
}

I ended up adding metrics inside the reference resolver, which is configured in the schema like the following:
import { addResolversToSchema } from 'apollo-graphql';
function resolveUserReference() {
// Resolve User + metrics
}
const referenceResolvers = {
User: { __resolveReference: resolveUserReference },
};
addResolversToSchema(yourFederatedSchema, referenceResolvers);

Related

Agenda | TimeoutOverflowWarning

Node.js Version: v12.13.1.
OS: Microsoft Windows 10 Pro, Version: 10.0.18362 Build 18362
NPM packages:
"agenda": "^2.0.2",
"appmetrics-dash": "^5.0.0",
"avro-schema-registry": "^1.5.1",
"avsc": "^5.4.16",
"await-to-js": "^2.1.1",
"bluebird": "^3.5.3",
"body-parser": "^1.18.3",
"dd-trace": "^0.12.1",
"debug": "^4.1.0",
"express": "^4.16.4",
"express-server-status": "^1.0.3",
"express-status-monitor": "^1.2.6",
"json-2-csv": "^3.5.2",
"kafkajs": "^1.11.0",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"mongodb": "^3.1.8",
"mongoose": "^5.3.3",
"mongoose-auto-increment": "^5.0.1",
"qs": "6.9.0",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"sha256": "^0.2.0",
"slack-node": "^0.1.8",
"socket.io": "^2.2.0"
I was running only agenda jobs. Almost all jobs are syncing data from other API's and saving all data to MongoDB. Sometimes after some time when I start the project, I get this error:
(node:26128) TimeoutOverflowWarning: 2591699977 does not fit into a 32-bit signed integer.
Timeout duration was set to 1.
at new Timeout (internal/timers.js:156:15)
at setTimeout (timers.js:142:19)
at jobProcessing (C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\lib\utils\process-jobs.js:258:7)
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\lib\utils\process-jobs.js:217:9
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\lib\agenda\find-and-lock-next-job.js:81:7
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\utils.js:414:17
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\utils.js:401:11
at ClientSession.endSession (C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\mongodb-core\lib\sessions.js:129:41)
at executeCallback (C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\utils.js:397:17)
at handleCallback (C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\utils.js:128:55)
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\operations\collection_ops.js:558:12
at handleCallback (C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\utils.js:128:55)
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\agenda\node_modules\mongodb\lib\operations\db_ops.js:516:5
at C:\Users\mailb\OneDrive\Desktop\DST\custom-market\node_modules\mongodb-core\lib\connection\pool.js:532:18
at processTicksAndRejections (internal/process/task_queues.js:75:11)
I ended up to install the "agenda": "2.2.0" version.
It reveals that i made a mistake in one of my instance where i didn't throw error, and it make the job infinitely process.
I advise you to try the same and run your server with --trace-warnings.
npm install --save agenda#2.2.0
node --trace-warnings yournodejsapp
Then, just see the logs and it will output where the error happen. Fix the error and you will be good :-)
FYI,
If you look at the agenda source code where the error is happenning.
// If the 'nextRunAt' time is older than the current time, run the job
// Otherwise, setTimeout that gets called at the time of 'nextRunAt'
if (job.attrs.nextRunAt < now) {
debug('[%s:%s] nextRunAt is in the past, run the job immediately', job.attrs.name, job.attrs._id);
runOrRetry();
} else {
const runIn = job.attrs.nextRunAt - now;
debug('[%s:%s] nextRunAt is in the future, calling setTimeout(%d)', job.attrs.name, job.attrs._id, runIn);
setTimeout(runOrRetry, runIn);
}
/**
* Internal method that tries to run a job and if it fails, retries again!
* #returns {undefined}
*/
async function runOrRetry() {
if (self._processInterval) {
const job = jobQueue.pop();
const jobDefinition = definitions[job.attrs.name];
if (jobDefinition.concurrency > jobDefinition.running && self._runningJobs.length < self._maxConcurrency) {
// Get the deadline of when the job is not supposed to go past for locking
const lockDeadline = new Date(Date.now() - jobDefinition.lockLifetime);
// This means a job has "expired", as in it has not been "touched" within the lockoutTime
// Remove from local lock
// NOTE: Shouldn't we update the 'lockedAt' value in MongoDB so it can be picked up on restart?
if (job.attrs.lockedAt < lockDeadline) {
debug('[%s:%s] job lock has expired, freeing it up', job.attrs.name, job.attrs._id);
self._lockedJobs.splice(self._lockedJobs.indexOf(job), 1);
jobDefinition.locked--;
jobProcessing();
return;
}
// Add to local "running" queue
self._runningJobs.push(job);
jobDefinition.running++;
// CALL THE ACTUAL METHOD TO PROCESS THE JOB!!!
debug('[%s:%s] processing job', job.attrs.name, job.attrs._id);
job.run()
.catch(error => [error, job])
.then(job => processJobResult(...Array.isArray(job) ? job : [null, job])); // eslint-disable-line promise/prefer-await-to-then
// Re-run the loop to check for more jobs to process (locally)
jobProcessing();
} else {
// Run the job immediately by putting it on the top of the queue
debug('[%s:%s] concurrency preventing immediate run, pushing job to top of queue', job.attrs.name, job.attrs._id);
enqueueJobs(job);
}
}
}

Access swagger path parameters from middleware

How can I retrieve a swagger path parameter from nodejs?
The swagger definition:
/objects/{id}:
x-swagger-router-controller: object.controller
get:
summary: Get object
operationId: getObject
consumes:
- application/json
parameters:
- in: path
name: id
type: string
required: true
What I've tried:
req.swagger.params['id'].value
req.query.id
Is there any dependency I need? My current dependencies are
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.12.3",
"morgan": "^1.9.1",
"swagger-express-mw": "^0.7.0",
"swagger-tools": "^0.10.4",
"swagger-ui": "^3.20.5",
"web3": "^1.0.0-beta.36"
}
Change this: req.swagger.params['id'].value --> req.swagger.params.id.value.
If you're using express framework and express router you can access request parameters by their name. For example this /objects/{id}: path parameter can be accessed like: req.params.id

bundle.js bundle.js:1 Uncaught Error: Cannot find module '/node_modules\mongodb-core\lib\topologies/../../package.json'

I am getting the below error:
bundle.js:1 Uncaught Error: Cannot find module '/node_modules\mongodb-ore\lib\topologies/../../package.json'
Here is my version detial:
OS: Windows10
MongoDB: 2.2.16
MongoDB-core: 2.1.2
Node: 6.9.2
I have used npm install bson-ext and changed \node_modules\mongodb-core\node_modules\bson-ext\ext\index.js to
try {
// Load the precompiled win32 binary
if(process.platform == "win32" && process.arch == "x64") {
bson = require('bson');
} else if(process.platform == "win32" && process.arch == "ia32") {
bson = require('bson');
} else {
bson = require('bson');
}
} catch(err) {
console.log(err)
// Attempt to load the release bson version
try {
bson = require('bindings')('bson.node');
} catch (err) {
throw new Error("js-bson: Failed to load c++ bson extension, using pure JS version");
}
}
while the original is:
bson = require('./win32/x64/bson');
because when I try browserify range.js > bundle.js, it cannot find bson-ext module in mongoDB-core.
I am not sure whether this kind of operation may cause the above error.
Here is my package.json file :
"dependencies": {
"browserify": "^13.1.1",
"bson": "^1.0.1",
"d3": "^4.4.0",
"express": "^4.14.0",
"hbs": "^4.0.1",
"jsdom": "^9.9.1",
"mongodb": "^2.2.16",
"mongodb-core": "^2.1.2"
}
I haven't been able to confirm this yet, but I think the problem is that MongoDB's JavaScript (Node.js) driver is not intended for use in a browser, for security reasons. Not clear if the problem in the OP is due to Browserify incorrectly resolving relative paths or something else, but regardless the preferred technique is to proxy requests to your MongoDB instance via a Node server.
Mongo lists off-the-shelf solutions for this here:
https://docs.mongodb.com/ecosystem/tools/http-interfaces/
Note also the --rest option, which allows an application to read directly from the DB via a URL schema:
https://docs.mongodb.com/ecosystem/tools/http-interfaces/#simple-rest-api
As the docs mention, this is not good practice for security concerns, but may help with prototyping.

Brunch with SugarSS (PostCSS parser)

How can I start using SugarSS parser with Brunch?
Here is the plugins part of my current config:
exports.config = {
...
plugins: {
babel: {
ignore: [/web\/static\/vendor/]
},
postcss: {
processors: [
require("postcss-cssnext")(["last 3 versions"]),
require("precss"),
require("lost")
]
},
cssnano: {
autoprefixer: {
add: false
}
}
}
...
};
And my package.json:
{
"repository": {},
"dependencies": {
"babel-brunch": "~6.0.0",
"brunch": "~2.1.3",
"css-brunch": "~1.7.0",
"cssnano": "^3.5.2",
"cssnano-brunch": "^1.1.5",
"javascript-brunch": "~1.8.0",
"lost": "^6.7.2",
"phoenix": "file:deps/phoenix",
"phoenix_html": "file:deps/phoenix_html",
"postcss-brunch": "^0.5.0",
"postcss-cssnext": "^2.5.1",
"postcss-scss": "^0.1.7",
"precss": "^1.4.0",
"sugarss": "^0.1.2",
"uglify-js-brunch": "~1.7.0"
}
}
The way PostCSS plugin for brunch works is, it's invoked after all the stylesheets were compiled and concatenated into a single file. (Brunch calls that an optimizer plugin)
Support of SugarSS or similar, however, will require creating of a custom compiler plugin, that will only transform sss into normal css.
It's actually easier than it sounds :) Use plugins.md as a plugin API reference. If it helps, take a look at stylus-brunch — https://github.com/brunch/stylus-brunch/blob/master/index.js.
What you'll basically need to change is:
compile() method, to invoke PostCSS with SugarSS parser and return a promise that resolves to an object with at least the data key (which in your case will be a string css)
change prototype.extension to be the extension you want to handle, sss in this case
you probably won't need stylus' constructor() and might not need the css modules support
you can release it so that other people looking to use SugarSS with Brunch won't have do this themselves. Sharing is caring, right? :)
(If you do go that route, it's customary to name brunch plugins with a suffix, like sugarss-brunch. You can also then include it in our list of plugins https://github.com/brunch/brunch.github.io/blob/master/plugins.json)
Hope this clears things up a bit. If you encounter any issues, feel free to either comment there or open an issue on our GitHub http://github.com/brunch/brunch

getting error with ember-fire: Assertion Failed: You must include an 'id' for undefined in an object passed to 'push'

I have a sample notebook app that works with ember-cli's HTTP mocks and also my rails backend using ActiveModelSerializer.
When I hook it to firebase with ember-fire, I am able to register a user (I see it in the dashboard) but when I try to retrieve it by email, I get the following warning:
WARNING: Encountered "0" in payload, but no model was found for model name "0" (resolved model name using ui#serializer:application:.modelNameFromPayloadKey("0"))
then this error:
Error: Assertion Failed: You must include an 'id' for undefined in an object passed to 'push'
at new Error (native)
at Error.EmberError (http://localhost:4200/assets/vendor.js:24735:21)
at assert (http://localhost:4200/assets/vendor.js:14636:13)
at Object.assert (http://localhost:4200/assets/vendor.js:22037:34)
at ember$data$lib$system$store$$Service.extend._pushInternalModel (http://localhost:4200/assets/vendor.js:75316:15)
at ember$data$lib$system$store$$Service.extend.push [as _super] (http://localhost:4200/assets/vendor.js:75302:34)
at push (http://localhost:4200/assets/vendor.js:94940:38)
at superWrapper [as push] (http://localhost:4200/assets/vendor.js:30984:22)
at http://localhost:4200/assets/vendor.js:70210:27
at Object.Backburner.run (http://localhost:4200/assets/vendor.js:9707:25)
I am querying the store using:
export default Ember.Route.extend({
actions: {
login: function() {
this.store.query('user', {
email: this.controller.get('email')
}).then((users) => {
if(users.get('length') === 1) {
var user = users.objectAt(0);
this.controllerFor('application').set('user',user);
this.transitionTo('notebooks', user.get('id'));
}
else {
console.log('unexpected query result');
}
});
}
}
});
Digging in, I can see by setting breakpoint at finders.js#157 I am about to
store._adapterRun(function () {
var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query');
//TODO Optimize
records = store.push(payload);
});
push the payload. The adapter payload inspects to
adapterPayload: Array[1]
0: Object
email: "test#test.com"
first_name: "Test"
id: "-K1oINClDw2ylQLww7-p"
last_name: "User"
which is my user. So all's good except for the trace. Not sure about that ID but I am new to firebase; maybe it's ok. It matches what I see in my dashboard.
I haven't done anything special with my serializer -- it's vanilla.
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
});
AFAIK I am using the latest & greatest -- here's bower.json
{
"name": "ui",
"dependencies": {
"ember": "2.1.0",
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.4",
"ember-cli-test-loader": "ember-cli-test-loader#0.1.3",
"ember-data": "2.1.0",
"ember-load-initializers": "ember-cli/ember-load-initializers#0.1.7",
"ember-qunit": "0.4.9",
"ember-qunit-notifications": "0.0.7",
"ember-resolver": "~0.1.18",
"jquery": "^2.1.4",
"loader.js": "ember-cli/loader.js#3.2.1",
"qunit": "~1.18.0",
"foundation": "~5.5.3",
"bootstrap": "~3.3.5",
"showdown": "~1.3.0",
"firebase": "^2.1.0"
}
}
and my dev dependencies in package.json
"devDependencies": {
"body-parser": "^1.14.1",
"broccoli-asset-rev": "^2.1.2",
"ember-cli": "1.13.8",
"ember-cli-app-version": "1.0.0",
"ember-cli-babel": "^5.1.3",
"ember-cli-dependency-checker": "^1.0.1",
"ember-cli-htmlbars": "1.0.1",
"ember-cli-htmlbars-inline-precompile": "^0.3.1",
"ember-cli-ic-ajax": "0.2.1",
"ember-cli-inject-live-reload": "^1.3.1",
"ember-cli-qunit": "^1.0.0",
"ember-cli-rails-addon": "0.0.12",
"ember-cli-release": "0.2.3",
"ember-cli-showdown": "2.5.0",
"ember-cli-sri": "^1.0.3",
"ember-cli-uglify": "^1.2.0",
"ember-data": "2.1.0",
"ember-disable-proxy-controllers": "^1.0.0",
"ember-export-application-global": "^1.0.3",
"emberfire": "1.6.0",
"express": "^4.13.3",
"glob": "^4.5.3",
"morgan": "^1.6.1",
"nedb": "^1.2.1"
}
Any pointers/help/guidance would be great! I am also new to ember too, so maybe I am missing the obvious?
You need a type key to be returned from your backend, rather than just sending an array. This lets Ember Data know what type of model you're pushing to the store. Your payload should look like this:
users: [
{
email: "test#test.com",
id: "abcdefg"
(...)
}
]
instead of this
[
{
email: "test#test.com",
id: "abcdefg"
(...)
}
]
Alternatively you can explicitly pass in the type and data:
store.push("user", store.normalize("user", response[0]));
(where response is still the array)

Resources