clentfort / urql-custom-scalars-exchange Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
This may be a result of #3.
Our case is like the following.
scalar Interval
type ThingWithInterval {
interval: Interval
}
Interval
is mapped to a corresponding type, like so:
type Interval {
start: number;
end: number;
}
From server to client (using Apollo), we serialize the Interval
like so:
serialize(value: Interval) {
return [value.start, value.end];
},
Then we deserialize the serialized-Interval using this custom scalars exchange like so:
Interval(v) {
console.log("Interval input: ", v);
return new Interval(v[0], v[1]);
}
The code runs the deserializer twice: once for each number
in the serialized array-version of Interval
.
For example, let us say the serialized Interval
the client got was [100, 200]
. Then the output from the console.log
in the deserializer would be:
Interval input: 100
Interval input: 200
Instead, we would expect the deserializer should run on the entire array. Then, the output from the console.log
would be:
Interval input: [100,200]
What I want is to set up not only how I want to process custom scalars, let say, parsing timestamps to Date in a centralized manner.
But I would also be happy to make Timestamp as an input field to get transformed from Javascript Date into milliseconds hence the Timestamp that backend expects.
Something like
scalarExchange({
schema: (schema as unknown) as IntrospectionQuery,
requestScalars: { // This is how to deserialize it back to original answer that server expects
Timestamp: (input: Date) => {
return input.getTime()
},
Date: (input: Date) => {
return format(input, 'YYYY-MM-DD')
},
DateTime: (input: Date) => {
return input // this one can be omited as Urql will run .toString() on this one anyway
},
}
responseScalars: { // This is how to handle them when they come FROM server
Timestamp: (input: number) => {
return new Date(input)
},
Date: (input: string) => {
return Date(input)
},
DateTime: (input: string) => {
return Date(input)
},
},
})
This one will make it super good to work with. Especially with graphql-codegen
that gives the ability to specify scalar types in TypeScript, so if you map Date
from GraphQL into Date
on TS side and then, you can serialize it using this extension and be super happy with it when reading (when Fragments will be supported tho as they're not now (issue alongside)), but when you then try to send/write in using mutation some field of type Date
and pass JS Date then you'll get a validation error as it will be converted to UTC string with time and timezone and not just YYYY-MM-DD causing you a headache :)
If this logic above will be implemented then it will be an amazing experience.
Please! :)
Just as the title suggests. Is there a way to serialize outgoing data?
The description shows that there is a scalars
option that looks like this:
scalars: {
Json(value) {
return JSON.parse(value);
},
},
Presumably, the name of the scalar is Json
, the serialized form is the value
and the parsed value is whatever that function returns. What if I now want to go backwards and, serialise a JS object into JSON before sending a request? Is this possible?
Many thanks for the repo! Still baffles me URQL and Apollo haven't got something like this natively...
A bug i've noticed is that this doesn't support nested Fragment's:
e.g.
query myQuery {
object1 {
fieldA,
...object1Fields
}
}
fragment object1Fields on object1 {
fieldB,
object2 {
...object2Fields
}
}
fragment object2Fields on object2 {
fieldC,
}
fieldA and fieldB are mapped properly, but fieldC is ignored. Pulling the field out of the object2Fields fragment and putting it directly in to object1Fields does however work.
e.g.
query myQuery {
object1 {
fieldA,
...object1Fields
}
}
fragment object1Fields on object1 {
fieldB,
object2 {
fieldC
}
}
I have an array of dates that are being sent over as strings but are not getting mapped using the custom mapper function. For example I have a schema of
dates: [LocalDate!]!
that comes over as an array of strings but the mapping function for LocalDate
is not run.
Here is my exchange setup.
import schema from '../../../introspection.json';
const scalarsExchange = customScalarsExchange({
schema: (schema as unknown) as any,
scalars: {
LocalDate(value) {
const date = new Date(value);
console.log(date);
return date;
},
LocalDateTime(value) {
const date = new Date(value);
console.log(date);
return date;
},
},
});
From looking at the source it looks like there's maybe code to handle arrays in the mapScalars
function but I'm not sure how to get the scalarMappings
in makeVisitor
/visitWithTypeInfo
mapped correctly to make it work in mapScalars
.
Would be happy to make a PR if pointed in the right direction, I'm just not sure what the correct solution is.
Just a heads up after bumping into this. The implementation doesn't yet take into account the existence of GraphQL fragments.
Hi,
When using custom scalars, we need 2 methods, one to map value when data is received by the backend (parse), another method to serialize value, which is used to send the data to the backend.
How can I achieve with using custom scalar exchange? Docs do not specify anything about this and also couldn't find anything in closed/open issues.
Can someone help?
I think it will be better to have @url/core
and graphql
as peer dependencies. It will make sure the library and the rest of the project use the same versions. I ran into a problem with types when the main project used @urql/core:2.0.5
and your library @urql/core:2.0.0
I am wondering whether this project is up for adoption. Several of the long-standing issues have been fixed in open PRs but haven't been addressed from maintainer-side and the project hasn't seen any activity on the default branch in 1.5 years.
@clentfort what is the status of this project and if it's unmaintained from your side, would you be open to have it adopted by a new group of maintainers? My employer uses this great exchange in several projects and we'd love to see it move forward again!
There were some breaking changes in 4.0.0
that make the interface incompatible, at least type-wise.
Error:
Type 'import("<path>/node_modules/@urql/core/dist/urql-core-chunk").Exchange' is not assignable to type 'import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").Exchange'.
Types of parameters 'input' and 'input' are incompatible.
Type 'import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").ExchangeInput' is not assignable to type 'import("<path>/node_modules/@urql/core/dist/urql-core-chunk").ExchangeInput'.
The types of 'client.operations$' are incompatible between these types.
Type 'import("<path>/node_modules/wonka/dist/wonka").Source<import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").Operation<any, import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").AnyVariabl...' is not assignable to type 'import("<path>/node_modules/wonka/dist/wonka").Source<import("<path>/node_modules/@urql/core/dist/urql-core-chunk").Operation<any, import("<path>/node_modules/@urql/core/dist/urql-core-chunk").AnyVariables>>'.
Type 'import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").Operation<any, import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").AnyVariables>' is not assignable to type 'import("<path>/node_modules/@urql/core/dist/urql-core-chunk").Operation<any, import("<path>/node_modules/@urql/core/dist/urql-core-chunk").AnyVariables>'.
The types of 'context._instance' are incompatible between these types.
Type 'import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").OperationInstance | undefined' is not assignable to type 'import("<path>/node_modules/@urql/core/dist/urql-core-chunk").OperationInstance | undefined'.
Type 'OperationInstance' is not assignable to type 'OperationInstance | undefined'.
Type 'import("<path>/node_modules/urql/node_modules/@urql/core/dist/urql-core-chunk").OperationInstance' is not assignable to type 'import("<path>/node_modules/@urql/core/dist/urql-core-chunk").OperationInstance'.
Type 'OperationInstance' is not assignable to type '{ readonly _opaque: unique symbol; }'.
Types of property '_opaque' are incompatible.
Type 'typeof _opaque' is not assignable to type 'typeof _opaque'. Two different types with this name exist, but they are unrelated.ts(2322)
Upgrading the dependency is needed. Types are broken when upgrading to Urql 2.0 but I do not believe any changes to the library are necessary.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.