GraphQL Nexus Schema (nexusjs) doesn't compile with scalar types - graphql

I am trying to follow the documentation on the Nexus-Schema (nexusjs) website for adding scalar types to my GraphQL application.
I have tried adding many of the different implementations to my src/types/Types.ts file using the samples provided in the documentation and the interactive examples. My attempts include:
Without a 3rd party libraries:
const DateScalar = scalarType({
name: 'Date',
asNexusMethod: 'date',
description: 'Date custom scalar type',
parseValue(value) {
return new Date(value)
},
serialize(value) {
return value.getTime()
},
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
return new Date(ast.value)
}
return null
},
})
With graphql-iso-date 3rd party library:
import { GraphQLDate } from 'graphql-iso-date'
export const DateTime = GraphQLDate
With graphql-scalars 3rd party library (as shown in the ghost example):
export const GQLDate = decorateType(GraphQLDate, {
rootTyping: 'Date',
asNexusMethod: 'date',
})
I am using this new scalar type in an object definition like the following:
const SomeObject = objectType({
name: 'SomeObject',
definition(t) {
t.date('createdAt') // t.date() is supposed to be available because of `asNexusMethod`
},
})
In all cases, these types are exported from the types file and imported into the makeSchema's types property.
import * as types from './types/Types'
console.log("Found types", types)
export const apollo = new ApolloServer({
schema: makeSchema({
types,
...
context:()=>(
...
})
})
The console.log statement above does show that consts declared in the types file are in scope:
Found types {
GQLDate: Date,
...
}
If I run the app in development mode, everything boots up and runs fine.
ts-node-dev --transpile-only ./src/app.ts
However, I encounter errors whenever I try to compile the app to deploy to a server
ts-node ./src/app.ts && tsc
Note: This error occurs occurs running just ts-node ./src/app.ts before it gets to tsc
The errors that shown during the build process are the following:
/Users/user/checkouts/project/node_modules/ts-node/src/index.ts:500
return new TSError(diagnosticText, diagnosticCodes)
^
TSError: тип Unable to compile TypeScript:
src/types/SomeObject.ts:11:7 - error TS2339: Property 'date' does not exist on type 'ObjectDefinitionBlock<"SomeObject">'.
11 t.date('createdAt')
Does anyone have any ideas on either:
a) How can I work around this error? While long-term solutions are ideal, temporary solutions would also be appreciated.
b) Any steps I could follow to debug this error? Or ideas on how get additional information to assist with debugging?
Any assistance would be very much welcomed. Thanks!

The issue seems to be resolved when --transpile-only flag is added to the nexus:reflect command.
This means the reflection command gets updated to:
ts-node --transpile-only ./src/app.ts
and the build comand gets updated to:
env-cmd -f ./config/.env ts-node --transpile-only ./src/app.ts --nexusTypegen && tsc
A github issue has also been created which can be reviewed here: https://github.com/graphql-nexus/schema/issues/690

Related

How to get GraphQL document validation error before launching a server?

I have some schema with simple misuse cases like on the picture bellow.
I was able to get them only via this stupid idea running apollo-server, as this was the first time when I saw them, so it would perform validation on create.
const { ApolloServer } = require("apollo-server-express");
const { readFileSync } = require("fs");
const typeDefs = readFileSync(process.argv[2]).toString("utf-8");
try {
new ApolloServer({
typeDefs: typeDefs,
debug: true,
mockEntireSchema: true,
});
} catch (error) {
console.error(error.message);
process.exit(-1);
}
I wasn't really able to get any validation cli tool which can accept only SDL definition and do this simple syntax checks. Are there any? I'm just trying to build build pipeline and injecting as many as I can into compile time, rather than runtime. I mean, hack is working, but this is so weird that there is no ready solutions for that.
I also using graphql-codegen for typescript, but it just doesn't care and no errors are thrown. The tool is okay with interfaces being used in unions.
graphql-cli with it's validate requires document and schema, but it's doing a bit different kind of validation.

How do i fix DEPRECATION: The matcher factory for "toHaveBeenTriggeredOnAndWith"?

Can anyone tell me what needs to be changed this test?
it('Should update settings of bar', () => {
const newSettings = {
dataset: [
{
data: [{
name: 'Category A',
value: 373,
color: '#1D5F8A',
id: 1
}],
name: ''
}
]
};
barObj.updated(newSettings);
const dataLength = barObj.settings.dataset[0].data.length;
expect(dataLength).toEqual(1);
});
I am getting this error from Jasmine and if i follow the link https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet i dont see exactly what i would need to change?
ERROR: 'DEPRECATION: The matcher factory for "toHaveBeenTriggeredOnAndWith" accepts custom equality testers, but this parameter will no longer be passed in a future release. See https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet for details. (in spec: Bar API Should update settings of bar)
I also cant find a lot of information about this message. I also dont have any custom equality matchers in the system. https://jasmine.github.io/tutorials/custom_equality
Try to update karma-jasmine package. It helped me.
I had this problem using "#metahub/karma-jasmine-jquery". You can modify the bundle in place and remove the second parameter from the `` toHaveBeenTriggeredOnAndWith" function. Or copy the module somewhere, uninstall "#metahub/karma-jasmine-jquery" and install the modified module: npm install ./#metahub/karma-jasmine-jquery

Apollo GraphQL Error: Query root type must be provided

I have an Angular/Apollo GraphQL implementation generating typescript code based on GraphQl endpoint which is surfacing a schema. I can hit the endpoint via Postman with a query and results are returned. However, when I run "graphql-codegen --config codegen.yml" via npm I get this error:
"Error: Query root type must be provided"
The server side is .Net Core implementation using GraphQL ASPNetCore. I have 4 different queries defined and each one works via graphiql.
Any ideas on why query root type is now being returned as null?
GraphQL must have at least one #Query() to be considered valid. So maybe only need add any Query to your Resolver code will be helpful.
Ex:
export class FooResolver {
#Query(() => String)
sayHello(): string {
return 'Hello World!';
}
}
This error throws when your schema stiching/definitions are incorrect. Please check the check your root schema definitions
https://www.advancedgraphql.com/content/schema-stitching
I was having the same issue while using graphql-codegen.
my codegen.yml is
overwrite: true
schema: "http://localhost:3001/graphql"
documents: "src/app/graphql/*.graphql"
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-apollo-angular
The issue was coming when I used the plugin typescript-apollo-angular.
I'm using Nodejs with graphql as backend.
The issue got resolved when I renamed the type
RootQuery -> Query
and
RootMutation -> Mutation
in backend schema.
Before
type RootQuery {
_empty: String
}
type RootMutation {
_empty: String
}
schema {
query: RootQuery
mutation: RootMutation
}
After
type Query {
_empty: String
}
type Mutation {
_empty: String
}
schema {
query: Query
mutation: Mutation
}
I ended up reverting back to a previous version of the codebase and reapplied my modifications manually and it works now. The only thing I can think of is I ran npm update which updated apollo-angular from 1.8.3 to 1.10.0.
EDIT Here is my code:
codegen.yml (used to generate code from npm command):
overwrite: true
schema: "https://to_end_point/Prod/api/v1/GraphQL"
documents: "src/**/*.graphql"
generates:
src/generated/graphql.ts:
plugins:
- "typescript"
- "typescript-operations"
- "typescript-apollo-angular"
./graphql.schema.json:
plugins:
- "introspection"
After reverting back to a previous version of Angular code then re-applying my code modifications, GraphQl code generation worked again. The only thing I can think of which could have caused this issue was when I ran npm update. Below is a screenshot of before/after of package.json:

Specify the webpack "mainFields" on a case by case basis

Webpack has a resolve.mainFields configuration: https://webpack.js.org/configuration/resolve/#resolvemainfields
This allows control over what package.json field should be used as an entrypoint.
I have an app that pulls in dozens of different 3rd party packages. The use case is that I want to specify what field to use depending on the name of the package. Example:
For package foo use the main field in node_modules/foo/package.json
For package bar use the module field in node_modules/bar/package.json
Certain packages I'm relying on are not bundled in a correct manner, the code that the module field is pointing to does not follow these rules: https://github.com/dherman/defense-of-dot-js/blob/master/proposal.md This causes the app to break if I wholesale change the webpack configuration to:
resolve: {
mainFields: ['module']
}
The mainFields has to be set to main to currently get the app to work. This causes it to always pull in the CommonJS version of every dependency and miss out on treeshaking. Hoping to do something like this:
resolve: {
foo: {
mainFields: ['main']
},
bar: {
mainFields: ['module'],
}
Package foo gets bundled into my app via its main field and package bar gets bundled in via its module field. I realize the benefits of treeshaking with the bar package, and I don't break the app with foo package (has a module field that is not proper module syntax).
One way to achieve this would be instead of using resolve.mainFields you can make use of resolve.plugins option and write your own custom resolver see https://stackoverflow.com/a/29859165/6455628 because by using your custom resolver you can programmatically resolve different path for different modules
I am copy pasting the Ricardo Stuven's Answer here
Yes, it's possible. To avoid ambiguity and for easier implementation,
we'll use a prefix hash symbol as marker of your convention:
require("#./components/SettingsPanel");
Then add this to your configuration file (of course, you can refactor
it later):
var webpack = require('webpack');
var path = require('path');
var MyConventionResolver = {
apply: function(resolver) {
resolver.plugin('module', function(request, callback) {
if (request.request[0] === '#') {
var req = request.request.substr(1);
var obj = {
path: request.path,
request: req + '/' + path.basename(req) + '.js',
query: request.query,
directory: request.directory
};
this.doResolve(['file'], obj, callback);
}
else {
callback();
}
});
}
};
module.exports = {
resolve: {
plugins: [
MyConventionResolver
]
}
// ...
};
resolve.mainFields not work in my case, but resolve.aliasFields works.
More details in https://stackoverflow.com/a/71555568/7534433

How to debug an import binding name that is not found

I have a NativeScript application that I'm trying to add iBeacon support to using the iBeacon plugin. The application builds successfully and is synced to my phone (I'm using SideKick). When the app runs, it has a fatal javascript exception. The javascript error is reported at:
file:///app/tns_modules/tns-core-modules/ui/builder/builder.js:244:56: JS ERROR Error: Building UI from XML. #file:///app/app-root.xml:18:9
That line is where the page that attempts to access the iBeacon code is defined:
<Frame defaultPage="views/search/search-page"></Frame>
and the specific error is:
Importing binding name 'BeaconLocationOptions' is not found.
I'm assuming this occurs as part of the following import statement:
import {NativescriptIbeacon, BeaconCallback, BeaconLocationOptions, BeaconLocationOptionsIOSAuthType, BeaconLocationOptionsAndroidAuthType, BeaconRegion, Beacon } from 'nativescript-ibeacon';
The above import statement is what is documented as part of the iBeacon documentation.
There is a nativescript-ibeacon directory under node_modules in my project. The specific ios file seems to be there:
/Users/edscott/NativeScript/beacon-test/node_modules/nativescript-ibeacon/nativescript-ibeacon.ios.js
I'm not sure if it is a problem in my code or a problem with configuration - maybe something missing that stops the ibeacon files from being deployed properly to the device.
My code is in javascript, but I have installed the typescript plugin. It looks like this iBeacon plugin assumes the app is written in typescript.
I'm looking for help in determining what to try next.
FYI...I've tried pulling the source files out of the node_modules and incorporating them directly into my project. After resolving many issues with this approach, I eventually hit the same wall - a problem importing the code when running on the device.
Below is the code that is using the iBeacon plugin:
const observableModule = require("tns-core-modules/data/observable");
import {NativescriptIbeacon, BeaconCallback, BeaconLocationOptions, BeaconLocationOptionsIOSAuthType, BeaconLocationOptionsAndroidAuthType, BeaconRegion, Beacon } from 'nativescript-ibeacon';
function SearchViewModel() {
let callback = {
onBeaconManagerReady() {
// start ranging and/or monitoring only when the beacon manager is ready
this.nativescriptIbeacon.startRanging(this.region);
this.nativescriptIbeacon.startMonitoring(this.region);
},
didRangeBeaconsInRegion: function(region, beacons) {
console.log("didRangeBeaconsInRegion");
},
didFailRangingBeaconsInRegion: function(region, errorCode, errorDescription) {
console.log("didFailRangingBeaconsInRegion");
}
};
let options = {
iOSAuthorisationType: BeaconLocationOptionsIOSAuthType.Always,
androidAuthorisationType: BeaconLocationOptionsAndroidAuthType.Coarse,
androidAuthorisationDescription: "Location permission needed"
};
let nativescriptIbeacon = new NativescriptIbeacon(callback, options);
let region = new BeaconRegion("HelloID", "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6");
const viewModel = observableModule.fromObject({
"beaconData": "not set yet",
"onTapStart": function() {
this.set("beaconData", "started");
console.log("tapped start");
if (!nativescriptIbeacon.isAuthorised()) {
console.log("NOT Authorised");
nativescriptIbeacon.requestAuthorization()
.then(() => {
console.log("Authorised by the user");
nativescriptIbeacon.bind();
}, (e) => {
console.log("Authorisation denied by the user");
})
} else {
console.log("Already authorised");
nativescriptIbeacon.bind();
}
},
"onTapStop": function() {
this.set("beaconData", "stopped");
console.log("tapped stop");
nativescriptIbeacon.stopRanging(region);
nativescriptIbeacon.stopMonitoring(region);
nativescriptIbeacon.unbind();
}
});
return viewModel;
}
module.exports = SearchViewModel;
I have created a playground for you here.
If you look into example, I am importing NativescriptIbeacon from the main folder and rest from the common folder.
P.S. This plugin has dependency on nativescript-permission
import { NativescriptIbeacon } from '../nativescript-ibeacon';
import {
BeaconRegion, Beacon, BeaconCallback,
BeaconLocationOptions, BeaconLocationOptionsIOSAuthType, BeaconLocationOptionsAndroidAuthType
} from "../nativescript-ibeacon/nativescript-ibeacon.common";
This answer solved my problem along with another modification. After splitting the import up I still had the same error. Then I read the following page about modules:
https://docs.nativescript.org/core-concepts/android-runtime/getting-started/modules
Based on this statement:
If the module identifier passed to require(moduleName) does not begin
with '/', '../', or './', then NativeScript will lookup the module
within the tns_modules folder
I assumed that maybe only require does the proper lookup into tns_modules.
I refactored the import to use require instead, and that worked. My changes are below. There may be a more efficient way to do this, but it worked for me.
const nsb = require("nativescript-ibeacon/nativescript-ibeacon.js");
const nsbc = require("nativescript-ibeacon/nativescript-ibeacon.common.js");
const NativescriptIbeacon = nsb.NativescriptIbeacon;
const BeaconCallback = nsbc.BeaconCallback;
const BeaconLocationOptions = nsbc.BeaconLocationOptions;
const BeaconLocationOptionsIOSAuthType = nsbc.BeaconLocationOptionsIOSAuthType;
const BeaconLocationOptionsAndroidAuthType = nsbc.BeaconLocationOptionsAndroidAuthType
const BeaconRegion = nsbc.BeaconRegion;
const Beacon = nsbc.Beacon;

Resources