Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Grats: A More Pleasant Way to Build TypeScript GraphQL Servers (jordaneldredge.com)
75 points by CharlesW on March 7, 2024 | hide | past | favorite | 77 comments


I've spent a lot of time with GraphQL, in the backend, frontend, and middleware, with TypeScript and also Python. At my startup, we used Strawberry on the backend, TypeScript in the middleware for stitching multiple APIs together [0], and codegen on the frontend with graphql-code-generator. Once we got it working, this was an amazing setup and my favorite part of our stack. GraphQL was a shared cross-language type layer with end-to-end auto-generation. We could define a resolver with Strawberry in Python, and get auto-generated types all the way to the frontend. We could collaborate on new features by defining a GraphQL schema in the RFC and coding the frontend and backend in parallel.

I recognize a lot of the problems described here in the docs (the "How Grats Works" [1] page is a good read). I could see this library fulfilling a similar role to Strawberry, for a backend written in TypeScript rather than Python.

Overall, it looks like a compelling implementation of some good ideas from the author, who incidentally is on the Relay team at Facebook, so he's probably done a lot of thinking in this problem space. Next time I'm working on a project with a TypeScript backend, I'll definitely take a look at this.

[0] https://www.splitgraph.com/blog/graphql-schema-stitching

[1] https://grats.capt.dev/docs/faq/how-grats-works


Grats author here: Strawberry was definitely (and continues to be) a big inspiration for Grats, I’m pleased to hear that you see the resemblance!


Did you manage to get IDE support to click into the backend implementation from the front end code?


No, that would have been cool though. We did have auto-generation on save of backend, all the way to the front. That was nice when it was just myself and co-founder, and I was doing a lot of fullstack code editing. But as we hired Python and TypeScript specialists, it became less important since each developer was only focused on their side. The interface, or "contract" between frontend and backend was the .graphql schema that we checked into the codebase. And if we needed to find an implementation, it was usually simple enough to grep for a matching resolver name.


Grats and Relay (I work on both) can be combined to get this developer flow, and it’s pretty incredible. Would love to see it working with Strawberry as well.

https://x.com/captbaritone/status/1748020699263045659?s=46

Example project with this setup working can be found here: https://github.com/captbaritone/grats-relay-example


At your startup, why did you choose Strawberry over, say, Prisma?


Mostly because the backend services were all in Python and already used Pydantic in a number of places. Prisma was just more heavyweight than what we needed.

We actually started with Postgraphile, but found it was too much magic and eventually moved to defining resolvers explicitly with Strawberry for each service (which was much easier to do once we added the stitching layer).


Interesting. Yeah, I also found Prisma to be a bit heavyweight. Postgraphile is nice, though. I wish it went beyond postgres.


My team has been using this in production for the past 6 months - this is the best way to write Graphql server in Typescript by far and I have tried it all


Removed


This is great, and I mean no disrespect, but aren't most servers written in anything but TypeScript? Java, Python, Ruby, .Net, Go, etc.? I recognize that changing it from "most servers" to "most GraphQL servers" brings in TypeScript, but I think that underscores the point I'm trying to make. Most HTTP APIs are REST (I think...that's worth checking) and will use something like Spring Boot, MuleSoft, Django, RoR, etc. In "enterprise" it's mostly going to be Java with Spring Boot or MuleSoft, or .Net. To have more GraphQL APIs, that's where the big game is: converting those REST APIs to GraphQL, or at least gradually (or not so gradually) persuading enterprises to switch from REST to GraphQL. With Spring Boot and MuleSoft, there's already a relatively easy story there: Spring GraphQL, Netflix DGS, MuleSoft Datagraph, graphql-java, etc.. There's probably something similar in the other ecosystems (Python, .Net, Ruby, etc.) You get to keep most of your code and development practices, but you do add in a few new libraries and you do write your code a little differently. So I just struggle to see what the audience is for TypeScript servers. Just my two cents.


There are maaaany backends written in JavaScript (nodejs), TypeScript is a much better alternative, and this is a step in the right direction (though I'm personally not a fan of GraphQL).


> There are maaaany backends written in JavaScript (nodejs)

Are there? I honestly don't know. I feel like it depends on how you count them. Are there JS/TS/nodejs "Backends For Frontends" (BFFs)? Yeah, I could see that, but then in that case there's at least as many other backends behind them, probably written in something else. Are there JS/TS/nodejs backends, mediating interaction with upstream databases in large enterprise organizations? I highly doubt it.


You are simply wrong. NodeJS is a popular server technology. I've implemented server APIs in NodeJS (both with and without GraphQL) in everything from large, well-known enterprises to brand new startups.


I could be wrong. That's one thing I'm trying to figure out. Setting that aside, like I said I don't really know that community, being mostly a Java developer. What're the go to database libraries? Is it sequelize, or something else?


There are tons of DB drivers/libraries for node. I'm personally a huge fan of slonik.


sequelize seems to be much more popular than slonik. Is sequelize more or less the standard or at least market leader?

https://trends.google.com/trends/explore?date=all&geo=US&q=S...


Sequelize is primarily an ORM. I won't get into a religious debate, but there are many good reasons for not wanting to use an ORM.

Slonik is much newer, and is Postgres only. But there is a general trend seen in many different projects that support safe SQL execution using tagged template literals in JavaScript, which is a fantastic technology. Slonik was one of the first projects that went this route, but there are now many others.

In general I think it's a mistake to look for a single "market leader" for node DB access. There are many high quality libraries that are favored by different teams for various reasons.


I'm just trying to get a sense of what tools are most commonly used.


Of course, Hibernate (Java) dwarfs them all.

https://trends.google.com/trends/explore?date=all&geo=US&q=S...


After a year-long job search, my sense was that (at least among hiring companies), TS was one of the most popular technologies and that was with a bias towards JVM-languages in my search.


In San Francisco, currently Indeed has ~2600 jobs for "Java", ~600 for "Typescript".


When I think “robust, performant language to serve traffic at scale,” my first instinct is definitely a frontend language.

I despise NodeJS and its entire ecosystem. The number of incidents I’ve been dragged into which are directly linked to its use is too damn high.


> I highly doubt it.

Not sure why you highly doubt it, when you admit 'I honestly don't know' and the truth is 20 seconds of googling away.

backend web frameworks - https://github.com/vanodevium/node-framework-stars

ORMs - https://github.com/emanuelcasco/typescript-orm-benchmark

Not to mention pretty much every major cloud service (AWS, GCP, etc) has first-class JavaScript/TypeScript SDKs.


I highly doubt it because I was talking about enterprise companies. I honestly have no idea how common node is in general, including other organizations, but when it comes to enterprise companies, I do have an idea. My idea is that node isn't very common. I'm even more confident in relative terms: however common it is, it's less common than Java and .Net are.

As for cloud service SDKs, are you saying that many node backends rely on cloud SDKs?


What's an 'enterprise company' lol? Many big banks have hundreds, if not thousands of nodejs-based backend services. Is Netflix[0] an 'enterprise company'? What about Walmart[1] ?

[0] https://www.bellcorpstudio.com/blog/how-netflix-is-using-nod... [1] https://medium.com/walmartglobaltech/migrating-large-enterpr...

> As for cloud service SDKs, are you saying that many node backends rely on cloud SDKs?

Almost anything that uses a cloud service like DynamoDB is going to 'rely on cloud SDKs'... the language is irrelevant.


Incidentally, I see no evidence in those links or elsewhere that either Walmart or Netflix is using node to meditate interactions with upstream data sources. What I do see elsewhere is the usual suspects: some databases and message queues, and then lots of Java

https://blog.bytebytego.com/p/ep76-netflixs-tech-stack


An enterprise company is a large company that's not a tech company: banks, health care, finance, manufacturing, retail, etc. The proverbial "FAANG" companies are not enterprise.

Netflix is not enterprise. Walmart is.

As for DynamoDB, is that database more common, or less common, than relational databases like Oracle and MSSQL?


That's a cool definition of 'enterprise company' you got there.

Maybe google 'enterprise company' after you finish googling which database is more common.


Ok. How do you recommend I go about Googling it, and what do you predict will be the results?


> which database is more common.

SQLite is #1 by far, with MySQL a distant second.


Not in enterprise companies, it's not.


I've mainly worked in startups, but also worked with big enterprises as well during a stint at Red Hat, and yes, backends in Javascript are numerous and plentiful. Aside from Java in enterprise environments, it's by far the most common backend I've seen.


I'm curious about that ecosystem, especially with regard to databased. I asked this elsewhere, but what're the main libraries for database access?


For databases it varies quite a bit. Among people who like to use an ORM, TypeORM is the current thing that is in widespread use. For non-ORM people, most use pg or a similar thin-layer on top of raw SQL.

In enterprise it was a lot of raw SQL as well, in large part because there was a lot of different DBs to support from db2 to SQL Server to Postgres


It's dodgy finding the right search term, but at first blush it looks like sequelize is most popular, though the gap has narrowed considerably.


They fall under a few buckets: Driver:

- node-postgres

- node-mysql2

Query Builder / Other thin clients: - knex - kysely - slonik ORM: - TypeORM - MikroORM - Objection.js - DrizzleORM - Prisma (actually runs a separate binary)


Notion (valuation 10 G$) and Asana (market cap 5 G$) are both nodejs down to the DB layer, to name two codebases I have personal experience with.

Not quite Fortune 500 tier, but certainly not small potatoes.


Well, I'm pretty sure I didn't say that nobody wrote node backends.


Yes, node/TS backend APIs are extremely common.


Are they more common, or less common, than Django and RoR?


LMGTFY


Did you forget the link?


Node.js is almost 15 years old at this point. JavaScript has been a mainstream server-side programming language used by experienced, thoughtful developers for a long time now.


I'm not talking about the developers. I'm sure they're wonderful people. I'm talking about the organizations. I don't believe node has been as popular for backends in the last 15 years, especially at enterprise companies, as Java and .Net have been.


Given that node is barely 15 years old that's not surprising.


Wait...is it "almost 15 years" or "only 15 years"? Is node old and established or is it still the plucky upstart?


Whichever one convinces you to agree with the opinion I hold.


So what? In all comments you seem hell bent on making a point but it’s not clear what the point is. JS backends are popular, and this is a GraphQL solution for them. The fact that JS backends are less common in enterprise companies seems completely irrelevant.


Do you want to meet people where they are and help them with solutions given their constraints?

Or, do you want to offer solutions using your preferred tools?

There are no wrong answers, as far as I'm concerned. I'm just curious which you would prefer.


If it’s closed source and for profit? Definitely meet people where they are.

If it’s open source, and only for self gratification then I’d use my preferred tools so I can convert more people into using my preferred tools and thus get a broader better community.


Building your backend/s and frontend/s in the same language makes keeping your data model, api inputs/outputs and business validation consistent much simpler and easier.


In addition, especially for smaller teams, there is huge value in teams that can easily go between front-end and back-end code.

Before I worked at an "all Typescript" shop, lots of times someone on the front end would need some small additional piece of data or an extra API call from the server team. They almost never did it themselves, and it wasn't so much that they couldn't read/code in Java, it's that the environment setups were so different. It just was rarely worth it to them to spend all the time setting up the backend environment (again, in a language they could understand but weren't "used to" in their day-to-day) to make a couple line change. Worse, some enterprising folks would set it up, but then since they only needed to make backend changes once in a blue moon, the next time they needed to make a change they'd have to spend a ton of time again getting their environment updated.

There is huge value to using the same language, and coding environments, across front and back ends.


I used to say the same thing, but after 10 years of using node on the backend I no longer think that's worth much. The amount of code sharing I've experienced has been pretty minimal. You can definitely architect your app around it to make it more useful, but with some rare exceptions, on the backend you are working with the entire dataset/database, and on the frontend you are working on a small subset. I just haven't found the amount of code-sharing to be significant because things are so different. The huge productivity gains of frameworks like Phoenix (Elixir) have in my experience far outweighed the gains from code-sharing. This is all just my personal experience of course, so I'd love to hear from others if this really ends up benefitting them enough to be worth it.


To emphasize, I agree with everything you've said, but I don't really think "code sharing" is the right metric. The important boost from my perspective is that it makes it much easier for front end devs to unblock themselves for relatively small issues, and it also makes it much easier for any dev to debug when they can easily follow the code through the whole stack.

E.g. in the past I've seen it take weeks (that is, one or two sprints' worth) to add a teeny bit of data to the front end. Reason being the request had to go to the back end team, then it had to get prioritized and added to the sprint, yada yada everyone's been there. When everything is in the same language I've seen front end devs be much less reticent to just make the change themselves.


Thanks yeah, ability to unblock yourself on the frontend is definitely a big benefit. Most of the places I've worked are "full stack" so this isn't usually an issue, but it definitely is in some situations.

As an aside, I've also kind of turned against "full stack" as largely unrealistic. There are of course exceptions, but most people seem to feel much higher affinity for one side or the other, and as a result often are just so much more effective and efficient when the scope is more limited to their comfort zones.


I have met perhaps a handful of devs who care about a good data model, or even know what one is.

Most seem to think that JSON is god’s gift to mankind, and that RDBMS are weird boxes you throw said JSON – along with random scalars for fun – into, and then you can blame the DB for being old and slow when your latency is abysmal.


> I have met perhaps a handful of devs who care about a good data model, or even know what one is.

Then you have worked with an abnormally large amount of shitty devs.


That may very well be a valid reason why people should build backends in node. But, people don't often listen to reason.


I don't really get the point of this comment. Even if most servers are not typescript, some are, and of those some may be interested in graphql, hence this.

The things you're mentioning see irrelevant if you're using typescript. You may be alluding to the question of why even use node, but that would be beyond the scope of discussion.


The point of the comment is to confront the following question:

"What exactly are we trying to do here?"

Are we trying to offer GraphQL servers? Or are we trying to offer GraphQL servers in Node? Because, if it's the latter, then I'll move on my merry way. If it's the former, then a new way of building GraphQL servers in Node may not be all that relevant if there's a majority of developers who already aren't building servers of any type in Node.


Do you know what's an easy, pleasant way to write GraphQL? Just write the GraphQL, in a foo.graphql file.


This approach works fine for simple projects, but you also need to provide an implementation, and the two need to line up. This is what leads people to want solutions that either generate implementation types from the .graphql schema or (as Grats does) generate the .graphql schema from the implementation.


You just point graphql-codegen[0] at your GraphQL.

0 - https://the-guild.dev/graphql/codegen


How is this different from Pothos, type-graphql or typegql? This announcement post doesn’t really have much to show for. I’d expect some comparison with other products that are on the market already


Grats author here. It's spiritually similar to type-graphql or typegql, except that it's able to see the TypeSCript types as well as the class/method names. So, there's less duplication, less overhead, and a less confusing API (specifying argument types and return in type-graphql for example is pretty confusing.

Unlike Pothos, this implementation-first approach is able to leverage simple type script names and types, whereas Pothos requires you to explicitly define all the names and types using their builder-pattern-for-graphql-SDL API.

More here on why Grats does not use decorators like type-graphql: https://grats.capt.dev/docs/faq/why-use-comments/


Another one I saw recently that looks really promising in this vein is gql.tada, which provides some very nice LSP support. Anything in the TS space endorsed by Matt Pocock immediately gets my attention!


gql.tada is indeed very impressive and I think shares many of the same values as Grats. That said, I believe that today they only support the client path. Editor features and type generation for queries/mutations and fragments, although they do have interest in having a server story as well: https://github.com/0no-co/gql.tada/issues/10


Thanks for clarifying and may I say it warms my heart to see the spirit of open, enthusiastic cross-project collaboration represented in that issue thread.


I think this is a cool tool, although my personal preference when working with GraphQL is to have it be a very thin layer over my graphQL agnostic API function calls.


Grats author here. That's supported as well. You can simply write annotated wrapper functions/classes/types/interfaces around your GraphQL agnostic API.


I'm honestly not sold on using comment blocks as a way of adding such annotations. IMO the use of decorators is more pleasant and flexible.


Grats author here. I agree, decorators would be preferable. However, decorators are a runtime construct and as such cannot be applied to type constructs. This means you can’t, for example, annotate an interface definition, or add a description to an argument (since arguments are declared using an object type literal).

You can read more about how I ended up settling on docblocks here: https://grats.capt.dev/docs/faq/why-use-comments


I don't think they'd work with TypeScript types because the types aren't actually retained in the compiled JavaScript but I agree. It seems kind of like a hack - usually you assume that comments aren't going to be executed or affect anything when the code is run, so it doesn't feel right when you use them to generate code.


The docs have a page [0] addressing this question. The tl;dr is because grats uses the TypeScript compiler to parse an AST, and the compiler already recognizes docblocks and attaches them to AST nodes.

[0] https://grats.capt.dev/docs/faq/why-use-comments


I would choose Garph (Zod + 0 build step or client side codegen) over this (Typescript + two layers of codegen for client side type safety)


That's the way!




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: