Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: TypeScript to GraphQL conversion tool with type inference (github.com/acro5piano)
90 points by acro5piano on Dec 26, 2018 | hide | past | favorite | 24 comments


An alternative to this and Apollo codegen is GraphQL Code Generator[1]. Like codegen it takes the opposite approach by generating typescript from graphql. It's similar to codegen, with the main two differences being 1) it's not centered around queries, it will generate types for all schema parts as well as queries defined client-side. This is useful for getting typescript types for all the individual schema parts without being "wrapped" in the type of a query, and 2) it's template based and relatively easy to extend modify how the code is generated.

[1]: https://github.com/dotansimha/graphql-code-generator


We use graphql-code-generator to make Typescript. We also upload versions of our typescript-query files (written separately from other client TS code) for each published version/branch (e.g. 1.1, 1.2, dev) and then can use an eslint plugin on the graphql server to validate it doesn't break backwards compatibility with existing client-side code (unless intentional). This has definitely saved us more than once.


Sounds great. Thanks for sharing!


What's the advantage of using this tool instead of apollo-cli/apollo-codegen?

> The main idea is to have only one source of truth by defining the schema using GraphQL-like object and a bit of helper class.

The source of truth already exists, and it's the schema.

Why do I need to specify the type in every query? What happens if I make a mistake and write the wrong type? What happens if the schema changes after I write the query? Will it somehow fail and force me to update it?


This is very interesting.

I have been writing a library [1] to bridge relational databases efficiently to GraphQL APIs, and adopted a similar approach towards eliminating the redundancy in the schema definitions.

I currently rely on io-ts [2] which I also use for runtime verification of configuration options in an attempt to facilitate type verification to both JavaScript and Typescript consumers.

[1] https://gql-dal.github.io/greldal/ [2] https://lorefnon.tech/2018/03/25/typescript-and-validations-...


GRelDAL is an interesting project! N+1 problem in GraphQL is difficult problem. It remind me Lighthouse PHP [1] which is a GraphQL framework top of Laravel. Lighthouse handles N+1 problem to create a lot of "union all" queries.

[1] https://github.com/nuwave/lighthouse


The solution we use at work is to put all of the GraphQL strings in separate `.graphql.ts` files. A script then scans the code base for such files, requires them, and converts queries/fragments into TypeScript types in a corresponding `.graphql.types.ts` file using apollo-codegen.

The advantage of this over plain .graphql files, or statically extracting queries, is that you can use all of the normal tools of TypeScript for composing queries (mainly imports and template literals), and you don't need to have globally unique names for all your queries and fragments. Having said that, I haven't looked at the recommended Apollo workflow in a little while, so I'm not sure if those issues still exist.


I didn't know Apollo codegen also interpret GraphQL in .ts file. Thanks!


> What's the advantage of using this tool instead of apollo-cli/apollo-codegen?

> Unfortunately I'm not yet able see any benefits you'd get over Apollo's codegen in return

> Doesn’t Apollo’s Codegen tool already solve this?

I am sorry for my late response.

I add the section to README.md which explains why I created this library even there is Apollo CLI's codegen.

https://github.com/acro5piano/typed-graphqlify#why-not-use-a...

In short,

- Simplicity make this tool works as expected

- Can handle multiple schemas

- Works without schema file

I wrote a lot there, but I just wanted to try the paradigm TypeScript -> GraphQL conversion, because there are no tools to do that, unlike GraphQL -> TypeScript conversion tools.

However, this is not just a hobby project, cause I use this in my current real world project, and it reduces a lot of boilorplate. So I submit here.

# I thought Apollo codegen needs .graphql extension and webpack loader, but it reads .ts files too... Awesome.


This is actually really interesting and mirrors a more general effort that I am pursuing[1] to build runtime representations of type in TypeScript, though my context is not so much GraphQL but rather just a more traditional HTTP API.

It looks like you try to keep it so that the runtime type object itself has the correct TypeScript type? That is, I would expect that under the hood you either have `types.number = 0`, `types.string = ''`, and so on and then you just use `typeof runtimeTypeObject` to derive this, or something more sinister like `types.number = ('number' as any) as number`. Either way that's fairly clever and I like it. I probably won't do it that way in `tasso` because one of my abstract points of power is that `tasso` should be able to validate that a given type object is a valid `tasso` schema, so there should be a metaschema. But it is really nice to have this thing saying just `typeof runtimeTypeObject` and not `ValueOfSingleType<typeof runtimeTypeObject>` to derive, from the schema's type, the instances' type.

I may steal one thing for `tasso` from this library, and that is the way your `constant()` works without specifying type metadata; I was under the impression that even with the `<t extends string>` TypeScript would still say "well `const x = constant('abc')` doesn't say anything else about `'abc'` so I am going to infer that it is a `string` and then string does extend string so `x` has type `string`," much like it does when you just write `const x = 'abc'`. I didn't realize that you can "hint" that you want the more generic type for the thing. In tasso this manifests when you are writing self-recursive schemas, like

    // the following line is a sort of hack
    const refs = tasso.refs<'cell' | 'list'>();
    // but then we can write stuff like this
    const schema = {
      cell: tasso.number,
      list: tasso.maybe(tasso.object({
        head: refs.cell,
        rest: refs.list
      }))
    };
It will be nice to replace that with `tasso.refs('cell')` and `tasso.refs('list')` without that "refs object", I think.

[1]: https://github.com/crdrost/tasso


Runtime Type Check looks very useful when developing a system which communicate with other systems, cause we cannot perfectly predict other systems output.

I am grad to give you some development hints!


Definitely looks interesting. I started with Apollo only a few weeks ago and am already tired of the redundancy and the verbosity.

I wonder how schema information/introspection from the back end could be used to improve this further.

Apollo has the codegen tool which uses the schema to automatically generate the required classes.


The first thing that popped in my head was also how this compares to Apollo CLI's type generation (https://github.com/apollographql/apollo-tooling, formerly apollo-codegen).

On a cursory glance, it seems like with this tool, you write a JS object in the same shape as the query, manually specifying the type of each field in that object, and then it generates the query for you to pass to graphql clients, as well as the types associated with the result of that query for you to use in your app. Whereas with Apollo's codegen, you write the query in graphql syntax, then run a CLI command to generate the types associated with that query for you to import and use.

It seems with this tool, you'd still have to manually state the type of each field (when that information can be perfectly inferred from the schema as demonstrated by Apollo's codegen), and you'd lose the ability to take advantage of tools that work with the graphql syntax to provide things like autocomplete based on your graphql schema while you're writing the query itself (https://github.com/apollographql/vscode-graphql, for instance). Unfortunately I'm not yet able see any benefits you'd get over Apollo's codegen in return. Happy to be enlightened if I'm missing anything.


That's my understanding as well. This would help for tools other than Apollo which do not have the codegen capability but as it is I'm not sure what the benefit is for Apollo users.


Apollo CLI isn't even coupled to Apollo Client though. You can use it to generate types for any graphql query as long as you can also provide a schema for it to infer types from.


Thank you for pointing out. I haven't used such tools, but with editor support we can do furthermore.

Type information can be perfectly inferred from the schema. I agree though.


> I wonder how schema information/introspection from the back end could be used to improve this further.

Yes, Apollo's schema validation is really awesome as we can find wrong type before we run code. I would like to add feature in the future.

Thank you for your suggestion!


Doesn’t Apollo’s Codegen tool already solve this? Works like a charm https://github.com/apollographql/apollo-tooling?files=1#apol...



Couldn‘t `json-schema` play major role in modeling the redundant things? FeathersJS goes this way....


As far as I know, json-schema just checks type in runtime right? I don't know how we let TypeScript check json-schema type in compile-time.


Is there a similar conversion tool for Flow types?


This looks great. Thanks!


Thank you!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: