How WunderGraph Simplifies API Development
How do you build apps in a landscape where most of your data is coming from different APIs? Jens Neuse, the founder of WunderGraph, is out to provide a solution.
Links & Resources
Click to expand the full transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of learn with Jason. Today on the show, we're bringing in -- oh, my god, I didn't ask how to pronounce your name. It's German? Is it Jens?
JENS: Yeah, Yuns is the more wrong version of the wrong version I've heard.
JASON: Okay. How should your name be pronounced. I'm so sorry.
JENS: The typical American version is Jens, which obviously is answer wrong. Yans I don't hear so much. The correct version is actually Yens.
JASON: All right. Well, off to a wonderful start on Learn with Jason today. We have Jens, thank you so much for joining us, how you doing today?
JENS: Yeah, it's actually a weird day because I'm currently in the hospital.
JASON: Oh, no.
JENS: I had some treatment. Nothing serious. But yeah, it's a bit weird with the Wi-Fi here and I really hope it holds up. But yeah, nothing to think too much about it. But it's a weird situation because I had to tell the nurses to not bother me because I had to do some important phone call. I didn't want to tell them I do a stream here. It's a weird situation.
JASON: Well, I appreciate you taking the time. Very, very grateful to have you here. So, for folks or not familiar with you and your work, would you like a give a background?
JENS: Sure. I'm in software engineering for 10 years. Before that I was a carpenter. Accidently, I had an accident can a track that ran over my knee. Which is also the back story why I'm here getting treatment.
JENS: That's fine. That pulled me into software engineering. I started building my first startup. I didn't have any formal education or I didn't study CS or anything. I just wanted to build a startup which completely failed because we had no clue what we were doing. But I learned a lot. And with that, I was off to a very interesting career. And I got super-interested in stuff like GraphQL and compiler and building API gateways and that ultimately led to building WunderGraph which at its very core is using an open source project that I've built over the last I think it's kind of like 5 years. Where I really started implementing GraphQL from scratch. From like lexing the tokens, parsing the normalization, building an AST. And figuring out how to use an AST to plan and optimize an execution plan and then to optimize that. This was really a side project. I just thought it was interesting to do. I didn't want to build a business at that time. I just found the project interesting to see what can I do with GraphQL? And yeah. Eventually it turned into a bit more. It turned into a product. I found an enterprise customer who was willing to pay me for support. And that helped me to raise the seed round and build WunderGraph with 13 amazing people around me. And yeah. Now we're building a company. It's super-exciting.
JASON: That's a very -- like, that's such a -- a different story than you usually hear with a startup, right? It's not the I had an idea and so I made a deck and I raised funding. It was, I was having fun and it sort of slowly grew into something that you felt needed to be, you know, that you could use the investment. It was actually a business. It's an emergent business as opposed to trying to come up with the idea and have a whole plan before you ever go raise funding. Kind of refreshing. I like that. So, how long has WunderGraph been around? You might have said this, but I think I missed the length of time.
JENS: I think the company, like from the moment we founded the company, I think it's about a year. But we are around much longer than that. The open source project exists. It exists longer because I started it just on my own. And it was kind of like a very long drag to actually get to the point where I can -- where I turn that into something real. So, I think it's about two years, probably. And in total, the problem space I'm working on is about five years.
JASON: Gotcha. Yeah. And so, WunderGraph is -- you mentioned a lot of sort of the process that things go through to make WunderGraph work. But the way that I have been led to understand it, and correct me if I'm wrong, is that WunderGraph is a way to bring together data sources from other places, right? Like I can plug in third-party APIs or other things into one central store in WunderGraph that allows me to then use WunderGraph as my source of truth as I build. Is that a good overview of how it works?
JENS: Yeah. I think it's actually very close. So, the basic idea is when you use -- when you write a Node.js app, how do you -- how do you -- let's say you want to use some code other than people wrote. How do you bring that code into your project? What's the typical way of doing that?
JASON: I mean, yeah, you write a fetch query. If you need something that's got secret keys you've got to set up a server or a serverless function. You're trying to figure out, like depending on what kind of Node app you're writing. If it's running on a server, you have server side functions with your data fetching, you have Axios and reach for something like that as well. All of which --
JENS: Let's say we want to import some code from another team or another organization or something. How would we usually do that?
JASON: Like a private npm registry or a monorepo. Copy-pasting in Slack which I've definitely been known to do.
JENS: Yeah. You know, and it's funny that you make this joke, but the point is... if you're writing code, and we want to add a dependency, we first of all we speak about dependencies. We speak about passage. We have something like npm. Npm install React, because we want to use React. Npm install Vue. And you made a joke, but the point is, when it comes to APIs, what we actually do is we copy-paste open API specifications over Slack. Or we take an open spec or a GraphQL schema and we upload that into -- interest a gist on GitHub and share that. Or even Stripe put their Open API Spec on GitHub, which is not really designed for things like an Open API Spec, just code. And if someone wants to import an API into their project, there's no npm for that. And that's essentially what we're building. Because there should be package management that could -- that should be dependency management for APIs. Because when I build an app, this is like from the past. In the past, when I build an app, I have absolutely no clue what APIs it depends on.
JENS: Because you install some SDKs, make a fetch, Axios there. Do you actually know what services you're depending on? And how are they wired together? And this might look like a small problem for one single project. But if you think of a larger organization with a hundred developers and so many applications they build, what APIs do their services depend on? And do they actually have a clue? And I think most organizations have absolutely no clue. Because the moment you do an Axios or a fetch somewhere in your code, you created an implicit dependency between your service and something else.
JENS: But it is not -- you know? And there's no package JSON file that tells you or API JSON that tells you, you just made that Axios. So, at the end of the day, we're building -- I don't know. An exponential number of dependencies between services and we have no clue about them. And I think that's massive problem because yeah, nobody know what is depends on what and we have no transparency. And actually, there's not just like one API style. There's actually many. So, we have like REST, we have So, we have Open API, we have Bristol, we have gRPC. And so, that adds even more complexity to the problem. So, I thought, yeah. That's something interesting to do. I want to make it simpler for people to work with APIs. And that's the -- the kind of problem I made the center of my life, essentially.
JASON: It's interesting because you -- you landed on this problem. And it sounds like you landed on this problem. You didn't work at a large company when you started working on this, right?
JENS: I actually did.
JASON: You do. Okay.
JENS: Kind of the starting point was I was working for T-Online, German's largest news website.
JENS: And the problem we had with T-Online, we this news website, and it's backed by the content management system, internal APIs of various API style. It could be REST API, it could be weird XML APIs. And then we had external data providers like football and weather and Formula One and all the different things you wanted on a news website. These were all didn't. And instead of actually August value to the website, what we did was we were gluing to the services and building backends for frontends, essentially. Which is the pattern to assemble a number of heterogeneous systems into something more homogenous that can be consumed from an easier way from the frontend and I thoughts that is not a T-Online problem. It's -- every company has to bring together data from multiple APIs, aggregate that, and think about how to bring it in an efficient way into the frontend. What I saw is that out in the world, everybody is building kind of their own home grown WunderGraph. And I thought it would really make sense to pull this code that everybody is writing, pull that into a library. Make it open source. And yeah. Find patterns that are very repetitive like combining data from two APIs. Or combining REST and GraphQL and SOAP. Like, very standard use case authentication. How do you it? Token auth? Cookie auth? And so on. So, yeah, what I really wanted to do was take all these patterns, come up with an opinionated approach and offer that as a framework so that everybody else can write less code. Or more on something important, sorry.
JASON: Yeah. Very, very much agreed there. Because I had -- I worked at IBM. And while I was at IBM, I had the exact same set of problems. We were working -- I was one of like three dozen teams that worked on IBM Cloud. And that team had sort of taken their monolith and split it into 32 copies and called that microservices and then they were kind of slowly pulling them down to just what was needed for each individual microservice. And they had the exact same issue where each of these teams was providing a set of APIs. But they were providing them in various different ways and they had no way of knowing who was using their API and the teams that were using them had no way of knowing how to change, were there are updates? How does this stuff work? So, there was this huge amount of work being done to keep things talking. Instead of work being done on building features. And we had whole teams dedicated to things like maintaining the, you know, just going around and doing upgrade work. You would rotate between all 30-something teams and embed with them to do a security fix and do a thing, and move to the next time. And by the time you got around, you had things to do again. They went around and around the circle. I worked on something similar to this that never went anywhere. It was like a GraphQL federation thing. Where I figured out that I could wrap all these microservices with a lightweight GraphQL endpoint that I could then stitch together so we could know who was using things and how they talked and whether or not there were upgrades. I don't bring that up to talk about that project at all outside of saying it's fascinating to me that these ideas were kind of -- they felt novel at the time. But mine was about 5 years ago as well. It's interesting that at the same time in the same space these ideas were emerging. And, you know, we saw things like a lot of GraphQL Federation stuff and a lot of -- a lot of different ideas that were sort of designed to solve the same general suite of problems. But this is the first time that I've heard of it thought of as package management. Which is such a good way to frame this problem. Like the reason that we liked Node and npm is because you had this clear map of like what dependencies were being used how to upgrade them and whether or not things were gonna cause problems in your codebase. Why don't we have that for data? Why don't we have that for third-party APIs and services like is that?
JENS: Yeah. Tell that -- we see?
JASON: You heard it here first, venture capital world! I think this is an interesting space and really provides some really interesting challenges. So, when you're working on this, how do you approach it when the world is so disparate. Like in npm, for example, there is a whole lot of trouble just keeping track of like CommonJS versus ES modules and making those interoperable. So, REST, gRPC, GraphQL -- how when you have this much complexity in the way people deliver data, how do you approach making that something manageable? How are you kind of smoothing this out?
JENS: Yeah. The answer is quite trivial. The implementation is extremely hard. And in fact, the implementation has grown to a point where it doesn't fit into my head anymore. So, you know, like 5 years ago when I was starting to write this code, it was like I understand every line of code. When you show me a bug, I can immediately answer why it is a bug. If you show me a bug today. So, don't worry so much about bugs. We have like, I don't know, more than 2,000 tests. So, I'm very much like a -- I wouldn't call myself a test-driven person. But this library is battle tested. The point I'm trying to make is, it's just grown over the years to a point where like I know like all the concepts and all the packages we have. But if you show me a bug, then I have to dig into it. And essentially, the short answer is you need to find some common ground across all APIs, and the way you can approach this is you can find some agreement where you say, okay. Our solution looks like this. Every API will return data in JSON format. So, they don't have to do that. It can be any other format. But we will treat it or transform it into JSON. Because then we have a common ground where we say, okay. Everybody talks JSON at the end of the day. The next thing is, you have to build a system where you can map out the different data sources and describe to the system how should we take an input and translate that into something the system will understand? So, the input in our case is GraphQL. So, the frontend of the compiler speaks GraphQL. And the backend speaks whatever you want. So, front, we speak GraphQL. We take a GraphQL AST. And then we translate this GraphQL AST into sub-ASTs that represent whatever the data source. And what is amazing about this architecture is -- so, we divide it -- the problem kind of like into a compiler problem. And the main thing about this is if you want to add a new data source, you implement a bunch of interfaces and that's really is. So, it's a very easy-to-extend architecture. We just recently added support for SOAP. We're currently looking into gRPC. We are also very interested in the future in supporting async API. And for each of those data sources, all we do is we implement the backend of -- yeah, of the compiler, essentially. And depending on what data source we're talking to, there are some -- some like different levels of complexity. So, for example, there are some data sources like REST or gRPC. They are very friendly because you make one request you get a pre-defined answer. Like with Open API, it is very clear, you make a request. It is very obvious from the JSON schema what you get back. Or protobuf. GRPC, it is RPC, you make an RPC call, you know what comes back. The problem is, and this is what took most of the years actually for me to understand and learn is how to build a proper compiler architecture for that is let's say you have a query that comes in on the frontend. And on the backend, what we actually need to do is we need to talk a Federated GraphQL Server. So, multiple microservices. And then a second GraphQL Server. And a third nested GraphQL Server and so, the complexity here is that when you -- when you have a frontend query, you actually have to divide that into multiple even possibly nested origin carries. How I call them. Or origin requests. And that means you need to parse the incoming A ST. You need to traverse every node and then figure out what GraphQL operations should I actually send to the origin? And that's really -- it's a very complex thing and it took me I think about four rewrites of the compiler architecture. And with the fourth rewrite, which is now -- I think it's more than two years ago -- it's kind of like very stable because we -- we figured out every -- all of the edge cases. So, yeah, for me it was like a super-interesting project. Now we're just adding data sources and fixing little bugs or making something a little bit faster here and there. Yeah, we're now mostly focusing on other layers. But yeah, I'm just -- I don't know. Engineer at heart and I really love to talk about this stuff.
JASON: Absolutely. Yeah. I feel that in my soul. It's very fun to just dig into the details and so, what I'm gonna do just to make sure that we have plenty of time is I actually think it will be more fun if we can start looking at this in action. So, I'm gonna switch us over into the pair programming view here. And I'm going to... before we get into it, let's do a quick shoutout, we have Amanda here from us from White Coat Captioning taking down the words. You can get the captioning in the CC in the video player. And the sponsors, Netlify, Nx, New Relic and Pluralsight making this show more accessible to more people which really means a lot to me. And we are talking about WunderGraph today. Let me get the WunderGraph site up and drop that into the chat. Hello, chat, how is everyone doing today? All right, Jens, from here, I want to start playing with WunderGraph. I want to play with it. Whats should my first step be?
JENS: Click get started.
JENS: And then click the 1-minute quick start.
JASON: All right.
JENS: Or you can go one step back. Because we can actually quickly go over something. So, we did actually two things with WunderGraph.
JENS: One is on the backend side, we connect to all the different data sources. And then the user progresses, or the usual way you deal with WunderGraph is you add your data sources, whatever you have. Then you define operations against those data sources. And the third step is that WunderGraph doesn't just build your API, but we also generate a fully-Typesafe client that handles all the data management, API stuff, authentication, file uploads, and other things. And we build integrations with Next.js, Remix, Svelte, Next, relay, everything that's cool. If you use one of those, you don't really have to do much for the API layer. And we will see that in a moment. We have too for mobile apps and currently we're working on super-exciting stuff with Relay. And it's coming out very soon. Yeah, let's click on the 1-minute quick start.
JENS: Okay. And then we have like a -- yeah. Okay. I don't like that snippet. I would suggest we use the sample project Next.js. So, if you copy that first line, NPX create WunderGraph app. And then you give is some name. And as example, we use just Next.js.
JASON: Okay and so, we'll call this WunderGraph-lwj. And the example is next. Like that?
JASON: Next.js. Okay.
JENS: Yeah, Next.js.
JASON: Okay. Here we go. So we can actually see it. Nice. Okay. So, we have a project. And I'm gonna go into it here. And then I'm also going to open. Project in here. Okay. So, here's our project. Oh, come on. So, we've got our project here, and I'm looking although --
JENS: You're one of those people who have the it on the right side.
JASON: I've done this for a very specific reason. Which is when I am showing code, I like to toggle this open and close. And it means the code doesn't bounce around.
JENS: Yeah. Okay. I think we need... yeah. You're a professional streamer, I can see that. Yeah. You need to npm install some Internets.
JASON: All right. So, let's get the dependencies in here. That will cause all these squigglies to go away. When do we get to the CSS? Benjamin, not today. You will not derail me today. I -- I have a tendency to start working on the CSS --
JENS: It was a bad idea that we have it here?
JASON: No, it's probably for the better. I start writing CSS and then start having fun and then spend 45 minutes. Okay.
JENS: Would you consider yourself more like a frontend Dev or more like a backend Dev?
JASON: I have worked in both roles. And so, now I don't really know. I call myself just generalized web Dev. Because I can do whatever -- I can do -- like I can get something built on the backend. I can, you know, deploy apps on servers or build serverless things. I've done a lot of work on building and designing APIs. And I've also spent a ton of time as a designer and working specifically on UX interaction. So, my career is very... wondering. I just kind of go where I'm interested right now and have ended up. I think that's why this job is perfect for me. I get to learn a little bit about a lot, which is very satisfying to my particular style of learning.
JASON: But okay. We've got -- we've got an app. So, we've got an app. We've got the dependencies installed. And I'm ready. What -- what should I do next?
JENS: I think it is -- what is if npm? Start or something. Npm run start, I think.
JASON: Let me double check. Npm start.
JENS: Yeah, it starts.
JASON: This is starting both WunderGraph and OpenCLI. What is this? I actually don't know what this one does? What is wait on?
JENS: That waits for about 500 milliseconds for this thing to listen on that port.
JASON: Got it. Okay. Okay. So, we've got the WunderGraph server is started.
JENS: I think you have something running. If you go to localhost 3K, we should see -- and Next.js app. That hopefully didn't explode.
JASON: It did not. I just need to move it to the right window here. Come on. You. Come over here. There we go. All right. So, here is our setup.
JENS: Okay. That's how we --
JASON: We did it. Here's our app. Running on localhost 3000.
JENS: Okay. So, that's -- that's the first step. I think the next step is that we make ourselves a bit familiar with the file structure.
JASON: Yes. Okay. Let me open this one up again. Didn't mean to open that. Let's look at this file structure. We have -- I see a WunderGraph folder. I'm just gonna start opening things. We've got generated stuff, we've got the pages. Users, public I'm not gonna worry about. Should I look -- is test something you want to dig into today?
JENS: We do it later. I actually have it --
JENS: Let me check my agenda. Testing is... yeah. Yesterday someone wrote in our Discord that the stream will be today with you and I was like, holy shit, I need to prepare something. I wrote a little agenda. Testing will come later.
JASON: Got it. Got it.
JENS: Okay. In general, so, we have this .WunderGraph folder. A lot of people are complaining that it's stupid, that it's dot WunderGraph. And it's correct. And we will at some point change it, but for the moment, we have a dot WunderGraph folder. It's a bit special. And every WunderGraph thing is in there.
JENS: Earlier we spoke about the package.json and the package environment. So, the central point for integrating APIs or the kind of package.json of APIs is the WunderGraph config TS.
JENS: And we can have a look at that. The most important bit, something I want to explain is you cannot just have a JSON or a YAML file to configure APIs. Because that just -- it absolutely doesn't work. It's -- it's the wrong tool for the job. Because if you integrate APIs, what you need to do is you need to -- sometimes you want to do mappings. You want to set headers. You want to manipulate result of the schema like this. So many different things you actually want to do. And ideally, you can do them in a mostly Typesafe way so that you have the IDE help you, assist you in your work. And so, that was like the core decision behind WunderGraph. So, all configuration is in code. And this also has very big benefits from my point of view. There's other tools that do this visually guided. Like we have a graphical user interface where you build data sources and stuff. But the point is, if you it in code, you can check the configuration into -- into Git. You have versioning out of control. out of the box. You can review changes in the pull request. And I think it's just -- it's a great way to do this. It is inspired by things like, for example, AWS CDK and Pulumi, and code, if we have that term. Yeah, what we're currently looking at here is you see that introspect, it's a big word for me. But I think it says "Introspect GraphQL." And that basically means we want to introspect the data source and then we say, configure WunderGraph application. And we pass this data source as an API.
JENS: And you can see, we can do some other things. We can configure code generation. We can configure our beloved course that everybody gets wrong. And that's probably like the biggest amount of commits in the world is probably because of course issues. And then there's other things you can configure like authentication and all this kind of stuff. We would come to that later.
JENS: And yeah. If you go back to this introspect GraphQL, you will notice one other thing. And that is there is an API namespace. So, we don't just introspect the GraphQL API, but we also give it a namespace. Could you guess why we do that?
JASON: My guess is that is what we use in the WunderGraph GraphQL endpoint so that I can say, you know, let me query spaceX and then get into the spaceX data.
JENS: Yes. So, that's -- that's very much on point. So, we didn't have that feature from the very beginning. But what we learned very early on or what I realized very early on is when you combine two APIs, it is very, very, very likely that they will both have the type user. Because everything has a user. And that's not the only problem you will run into. And so, if you build a GraphQL schema from multiple APIs, what will happen very early on in your journey is you will have some naming conflicts and you don't know where this type is coming from and that field. And so, essentially, we namespace all APIs. And that's a concept, again, we borrowed that from -- from npm. And other ideas. So, it's not something we invented. But namespacing things makes a lot of sense and so, yeah, we imported the spaceX API. We import this to our APIs. And then you can go to the folder operations, which is another convention.
JASON: Okay. Going to operations.
JENS: And inside operations, you can great GraphQL files. So, for example, the dragons GraphQL where you simply write a GraphQL query. By the way, do you have type safety? Do you have the GraphQL extension installed? Like if you try to type something below active, for example?
JASON: Let's see if I have it. I have... syntax highlighting. Which extension do I need?
JENS: I think the first one is the better one.
JASON: So, I have -- oh. Language feature support? Okay. Let me install this one real quick.
JENS: Yeah. I think it's from the GraphQL Foundation, right?
JASON: Yes. And so, I have this now. And if I come in here and do one of these, there is --
JASON: Our autocomplete.
JENS: Okay. So, yeah. You can change that here or do anything you want. Okay. That's great. So, there is actually two ways of defining operations in WunderGraph and what I have to explain is, WunderGraph exposes either a GraphQL API, but most of the time you don't really want to do that. Most of the time you actually want to expose operations. And operations are simply -- it's simply JSON RPC endpoints. So, this operation which gives us name and active from dragons, that is an operation. And what we can actually do --
JASON: Can I?
JENS: Yeah, go ahead.
JASON: I want to pause you real quick because I want to dig into that a little bit. So, you don't want to expose a GraphQL query. You want to expose an operation. Why is that important?
JENS: Okay. Let's say you are in your IBM job and you deploy a frontend and it uses GraphQL. After deploying the app, are you going to change the GraphQL operations?
JASON: You wouldn't be able to, right?
JENS: So, the answer is no, right?
JENS: So, you deploy something that you will not change. So, the frontend will not dynamically generate GraphQL operations. So, what's the point in opening up a dynamic query interface to the Internet when you actually don't need it? Because all you need to know is there is a piece of code in my frontend that wants to call this spaceX dragons operation. And we expect that it contains name and active as fields. So, if we can take all this information and run it through a compiler, which I like compilers, then we can actually remove GraphQL from the runtime and it makes it more secure, we're transferring less data. The query is actually not a post, it's a get request. You can cache it with a regular HTTP proxy. And you don't lose anything because, yeah. It's really just -- like it feels and looks like GraphQL. You can even use a more advanced like relay. But yeah. There's no reason for most applications to expose a GraphQL API at runtime.
JASON: Got it, okay. And so, the reason for that being that if it's an operation, you're able to do a lot of the work ahead of time and effectively say, here's a reference to this query. And any time somebody use this is reference, run this query. As opposed to letting somebody just arbitrarily write whatever query they want. And okay. So, that totally makes sense. And this is -- this is something that's not unique to -- to WunderGraph. Like the idea of operations. Because I remember there was also things like named queries or -- I can't remember exactly what the jargon was for it. But the general idea being, if you know what the queries are that are gonna be executed against your app, then the best -- the best practice is to just have those queries ready to go instead of expecting your app to form those queries because it just eliminates a lot of complexity and potential headache.
JENS: Yes, there is something --
JENS: Which is called persistent operations.
JASON: That was the one I was thinking of.
JENS: Yeah. This -- by the way, it is very important that you say "Persisted operations." Don't say "Persisted queries." Because a persisted query can be a query or operation. If a persisted query is a query, then it's a persisted query-query and that's super-weird. Yeah.
JASON: Got it, all right. So, we are designing -- we're defining these as operations effectively so that WunderGraph can do as much optimization behind the scenes.
JENS: Yeah. But not just optimizations. For example, let's add... let's add a variable to this dragons operation.
JENS: So, after dragons, you can do a variable definition.
JASON: What do I want to get?
JENS: Oh, that's a good -- can we first try out what kind of variable could be of use? Because GraphQL doesn't allow unused variables. So, that spaceX dragons, does it allow us to put any variable? Is that -- can we make like a --
JASON: That's a good question. Oh, yeah --
JENS: Make a bracket after that.
JASON: You have a limit and an offset.
JENS: Yeah. Limit. You can do like a limit. Okay. That's good.
JASON: Okay. Limit and then I can set up a --
JASON: Limit. That will be a integer. Okay.
JENS: Yes, okay. That's awesome. And save this.
JENS: And now what WunderGraph does, is we don't just do persisted operations. We do so many other things. But you can look into the generated folder and it has some interesting stuff for us. So, for example, one thing you can look at is there is something, I think it's like JSON schema.
JASON: Ah, interesting. Okay.
JENS: Yes. And if you scroll down a bit, you can see for the dragons operation, the input is now a -- if you scroll up a little bit, you see the input.
JASON: Oh, here.
JENS: Properties, limited, type integer. So, we didn't just store a procedure or something. We also create like a JSON schema. This JSON schema is now used on our server to validate the input. You can do regX or something to export it. You can import it into a frontend library that understands JSON schema and create a form from that.
JASON: Oh, cool.
JENS: You don't even need to write manual forms anymore.
JASON: That's -- okay. All right. All right. Now the gears are turning in my head. I'm seeing -- I'm seeing the value here. Like this is -- you know, it's one of those things that when you first look at a tool like this, it's very easy to try to dismiss it as, oh, I've built something like that. And then when you actually start looking at all of the little things that you have to do to work with data. You have to be able to, like not just query and display the data. But you also need to be able to change the data over time. You need to be able to do things like add a variable and then know that all of your queries across the app aren't about to break. Like using form inputs, that's not something I would typically think of as being part of the data layer. That's something I would think of as an entirely separate project. But having those tied together well enough that I could just grab a library that could read the schema and build me a form. And now all I have to do is CSS, which we all know I love so much. That -- that's -- it's like layers of value. It's not like here, this is just for your data. This is like, wait, hold on, this is gonna make the whole process feel a little more tightly coupled. Or more tightly integrated. It's gonna feel more like one process that's all aware of itself and the code starts to feel smart. It's like the magic of autocorrect, but across layers of concerns.
JENS: Yep. And to just show you another way where we leverage code generation and just the data we have, do you have Postman installed?
JASON: I do.
JENS: Let's open Postman.
JASON: I wonder what I was doing in postman the last time I was in here. Let's make sure I don't have anything -- let's see. All right. There's Postman.
JENS: Okay. And then somewhere on the top left, there's like three dots and you can say import or something. Collections. Can you go to collections?
JASON: Here's collections.
JENS: Okay. And then you say import.
JENS: And now you open the WunderGraph-generated directory somehow.
JASON: Let me make this small again. I've got the WunderGraph-generated directory.
JENS: And there's something Open API JSON.
JASON: Open API.
JENS: We also have a Postman collection. But you can -- I think the Open API has better quality.
JASON: Okay. And so, do I want to this -- this URL here?
JENS: Ah, no, you just take the file and drag it into this drag and drop thing.
JASON: Oh! Very cool. All right. So, let me find this in the finder. And then I will drop this right into here. And looks like I've got two options. A Postman collection or Open API 3.1 with a Postman collection.
JENS: Yeah. I don't know. Choose -- choose either one. I think they are both --
JASON: Okay. I'm just gonna hit the button. All right. So, now I've got... dang. That is -- okay. So, that's really cool. So, I've got value of integer, null.
JENS: And maybe, yeah. You can just try out with your dragons and put in something. And then run that. And --
JENS: The point is, you now created API documentation for your WunderGraph API. But you --
JENS: But you don't need to do anything, it's just here.
JASON: Yeah, that's pretty slick. Like that is definitely the sort of thing that I -- I definitely have spent a lot of time trying to make something like this work. And it immediately went out of date because as soon as I stopped working on it, we worked on something else that broke this. And so, knowing that this is generated as part of what's in the project. That's -- that's powerful stuff. Like this is -- this is definitely the kind of stuff that makes a big difference.
JENS: So, you know, if you're building a small app and, you know, I build a small API. This is a utility for someone else and I want to share it with them. You really just create one operation and it can be GraphQL, it can also be TypeScript. You deploy that thing. You take that Open API Spec or the Postman collection. You share it with that other person and they now understand how your API works and they can try it out with Postman or cURL or whatever and I think that's huge.
JASON: Yeah. That's extremely cool. Okay. So, what should we do next?
JENS: So, we created this API and we saw, okay. We can -- we can use Postman to try it. Let's now have a look at our frontend. How will we call that actually from the frontend?
JASON: All right.
JENS: So, in this case, we are making an integration with Next.js. And we have this index thing here. And you can see there is this use query that's a predefined hook. And if grow operation name, you will realize this is autocomplete. Or this has autocomplete.
JASON: Oh, nice. All right. So, let me delete this. And... it's thinking. Let me try that again.
JENS: It's taking a bit longer.
JASON: Yeah. I don't know what's going on. There grow. Okay. And so, then --
JENS: Okay. Now it works. Yeah. And then if you type after that, if you type input. We have the optional input. And then I think there you can define an object. And we had limit. Which is optional. And then you can add a limit. Save that. Check out our browser and then it should not be two dragons, but rather one, right?
JASON: And if I update this to two again. There's our two. Very cool.
JASON: Autocomplete your way to victory is one of my favorite ways to code.
JENS: Yeah. So, that was a very simple integration. And we can now level this up a little bit.
JENS: So, I've prepared one snippet. I will drop that into -- one second. Here into the chat.
JENS: I hope that works.
JASON: All right. This is gonna look a little wild. We're -- so, I have it on my clipboard, where should I put it? In the WunderGraph config?
JENS: Yeah. Go back to the WunderGraph config. Yeah, exactly here. So, put it there.
JASON: Okay. I'm just gonna let autocomplete save us here. And now I have Federation Cloud upstream. I've got account, products, reviews and inventory. And that gives us a Federated API which looks like it's bringing in --
JENS: And we need to pass that to our APIs.
JENS: Okay. And once you save this --
JASON: I'm already really excited about this. Because this just did a thing that I have always considered to be very important and extraordinarily hard. Because we are stitching together what looks like four internal microservices into one API. Within the scope of the app. And that feels really good.
JENS: Yeah. So, these microservices, they are compatible. So, they use Federation. And the interesting bit is actually that we can now, like, we can now use SpaceX and this Federated API side-by-side. So, what we can -- what we can just do in our operations further, we can just do -- create a new folder. Let's just call it demo or whatever you want.
JENS: And let's create a new -- let's create a product .graphql file, for example.
JENS: Okay. And here, you can just start with the query. And see if you start typing Federation.
JASON: Do I need it to restart to pick that up?
JENS: Yeah. We need to see. Can you -- can you check the -- in the generated folder, there's a GraphQL file. Can you check that?
JASON: GraphQL file, schema.
JENS: Yeah. This one. And if you search for Federated.
JASON: It looks like it did not get picked up automatically. Oh, wait. What don't you like? I forgot about something. Introspecting GraphQL API for namespace, Federated failed. Connection refused. Should I... try again?
JENS: Can you check the code we're actually using to make it? Do you see an obvious -- oh! This is -- is the HTTPS missing in front of -- yeah. How did that happen?
JASON: All good. Let's see...
JENS: You know what is weird? I sent this in the -- in the chat of the stream. And somehow the --
JASON: It stripped it.
JASON: Yeah. It's very helpful that way. Okay. So, let's go back in here. Try a query again. We'll call it products. Go for --
JENS: But I think the buttons are still a bit angry. Like maybe we need to give it another -- a reboot.
JASON: Yeah. All right. Let's give it a shot and see what... it can not load operation demo products. GraphQL document must contain exactly one operation. And that would make sense because... I'm just gonna delete this for now. Let's -- let's get rid of this one. And let's try again. Server --
JENS: You're a tinkerer. You can fix problems on the fly.
JASON: Okay. So, now it's -- I'm just gonna stop and restart it one more time to make sure that it actually worked. It looks like it's working.
JENS: Yeah, I think so.
JASON: I'm not seeing any errors.
JENS: If you want to check the GraphQL schema, we should be able to see if there's a --
JENS: If there's something with Federated.
JASON: There we go. We got Federated now.
JASON: That means we can go back in here and create this products.graphql. And then in here, I'm gonna go to create products, and we will grab that Federated. Where are you at? Do you need to reload?
JENS: It should be here.
JASON: Yeah. It's definitely in there. And so, why...? Federated top products.
JENS: That's definitely not anything. But.
JASON: Yes. So, this feels like it is not picking up my changes. Which means I need to make it update. Configure file, configure... you're already there. So, why don't you like this? Come on, now.
JENS: Maybe you need to reboot the LSP or something?
JASON: Yeah. Let me... let me just... for now, we'll just empty this out. And that's probably gonna yell at me again, but I'm going to close VSCode.
JENS: I could try to send you a query if that helps.
JASON: I can fake one if I need to. But we'll... let's get this open again. Open. Open this one again. And in here, now... you little punk. There it is. There we go. All right. So, we've got top products. And we'll get like the name and the price. And is that -- do you want me to grab anything else?
JENS: Oh, no. That's enough for just demo purposes. So, if you want, we can go back to our frontend.
JENS: And here instead of dragons, you can now check out what else we have. So, we should see, I think, it should give us -- the Federated operation.
JASON: Unhappy in my IDE right now. It should be giving me all of that. For whatever reason, it really doesn't like something we're doing in here. But it's unclear on what that thing is. Oh, it's -- what is that? Why is this thing struggling so hard? Knock it off. Okay. I'm just gonna --
JENS: I think now it's fine again.
JASON: There's dragons. But see, it hasn't picked up that new operation yet, which leads me to believe that it's doing something -- it's not running is why. That would explain a lot. Okay. Okay. Okay. Everything's fine. We're doing great. Okay. So, now that I've got this, here is our demo products. And then in here, we don't have any inputs yet. So, I think we can just see --
JENS: You make me sweat, Jason.
JASON: I apologize. All right. So, here's our -- our dragons. And we'll just throw our products in there. And now, if I go and look at the home page, we've got products. Okay. So.
JASON: This is exactly what we wanted.
JENS: So, yes, great. Next, let's level this up a little bit.
JENS: The next exercise we do is -- I send you another snippet. And we want to -- we want to go a little bit custom. We want to --
JENS: Combine data from multiple APIs in this -- in this next challenge.
JASON: Okay. So, I am going back into my WunderGraph config. And I'm gonna drop this down here. Let that autosave. Don't know why that's not...
JENS: It's probably. It did the thing again, yeah.
JASON: Okay. So, we'll... hit those. But why on Earth -- look at that. It's not saving. Is this the day that my computer goes into open revolt? Like what is happening right now? Come on, now. Okay. Copying. Don't save. We're going to quit VSCode entirely and try this again. Okay. All right. So, then I'm going to attempt opening VSCode one more time. And we're going to -- it's already got that one open. So, we will get back into this config file. And we'll drop this back in. Okay. Now it actually saved. Good.
JASON: We've got the pieces.
JENS: The countries API, you have the weather API. You add those two.
JASON: Okay. So, I'm gonna add these --
JENS: And don't forget to --
JASON: Npm start that.
JENS: Don't forget to add them to the API array, right?
JASON: Okay. And so, we're going to add countries and weather.
JENS: Yep. And then in line 40 -- or after line --42, can we make a new line and then we add one more thing? So, type "Experimental." And make it an object. Just an object. And then I think there's ORM. Yep. And set this to true. Because I want to show you something that we have been working on for a couple of months. And I'm super-excited that it finally was published last week. Because what we realized when we started with WunderGraph, the first approach was that you can use GraphQL to write operations. And eventually people came to us and said, yeah, that's great. But I want to be able to customize an operation. I want to write some custom code. So, we said, okay. We give you TypeScript operations. Which are very much similar to -- similar to tRPC or just RPC functions. And so, we wanted to allow a user to interact with their API dependencies. We call that a virtual graph. Virtual because we expose it. So, we wanted to make that accessible in TypeScript functions. And we create an ORM, it takes all your data sources and we're generating a TypeScript ORM. You don't even need to use GraphQL anymore. And that's what we're gonna do in our operations folder in the demo. You can just create whatever TypeScript file. Like, I don't know.
JENS: Just call it custom.ts or whatever you like.
JENS: And then you do an export default. And then you type "Create operation" and do an import. And then you say dot query. Yes. And make that a function, pass it an object. And here you can pass a handler. So, you can define a handler which is an async function that takes a context.
JASON: Async and it takes in context as the top level argument, like that?
JENS: Yes. And I don't know why, but this happened to me as well. This .Wundergraph import is wrong, it's dot, dot, or dot, dot, slash -- yeah. Without the .Wundergraph. Now that's correct. In this context, we have a thing that's called graph. We can say context.graph and then you can say .from. With from, you're selecting the namespace. So, in this case, Let's start with countries. And then go next and we say query. And here we can say what we want to query. So, you can just pass it a string.
JENS: And let's say we want to query a country. And you can say where? pass it an object. And you can say DE for Germany.
JASON: Upper or lower?
JENS: Yeah, upper.
JENS: And finally, dot exit. Fine.
JASON: Like that.
JENS: And Germany, you can await that at the beginning of the line.
JENS: Let's put this into something like const country equals whatever. Okay. And we can return this. So, you can just say, return country. Okay. And we save that. Some formatting, nice. Okay. Let's try this out somewhere. Why don't we write a little test for that?
JASON: Write a test. Got it. Okay.
JENS: We have in text, we have index.test.ts. And this is another thing where you can see, like, yeah. WunderGraph is easy. But we also have a generated test suite. So, you can see here we have a Ouija test server is that we start and call, and type safe operations. We can replace that with our test, whatever thing. And this way we can actually test our API with just --
JASON: Okay. So, I've got the test. And we'll say country and... so, const result of await, WG client. Query. And I want the operation name of demo custom. And I expect results -- oops. -- result.data at...
JENS: You can say code? Code must be DE.
JASON: Okay. DE.
JENS: Okay. Now you can stop the process that we were running before, just stop this. And you can run npm run test.
JASON: We did it! All right. So, we wrote a test. And if I --
JENS: You know your integration is working. Let's try it, that's a good point.
JASON: And now... oh, I broke it. Okay. So, something I did is wrong. Oh, do I have to -- does it need to be -- does the server need to be running to like regenerate the start procedure?
JENS: You need to -- go to the package.json. And here there is WunderGraph -- where is WunderGraph built? Yeah, just build WunderGraph.
JASON: Okay. Ah, so close. So, close on the spelling. At -- and now it's gonna -- it's gonna actually break the way we expected. Because it's compiled that test and -- or it compiled that operation. And is getting the wrong thing. Yes, exactly oh, received undefined. Who knows why the US didn't show up as a country or maybe I put the wrong one in. Who is to say? Let's... oh, wait, that won't do anything. Okay. That's -- you know what? We -- we got it running. It was matching the thing properly. And now if I test it again, with the DE. It should work. Oh, interesting. Something... it like lost the ability to get the country. I wonder if it's missing -- is there something else that needs to run for it to fully generate?
JENS: I'm not sure. Maybe we messed up something. But yeah.
JASON: You know what? It's fine. We had it running and then I went off -- I went off the trail. And that's... that is okay. What I can also do is I've got this running now. And I can run test in a side window here. Yeah. And then it actually starts -- so, I think something was up with exactly what we were doing there. But then if I do this... save it. Run test. And it says, get out of here. That's incorrect. Okay. Perfect. Cool. Okay. So, we've got a running custom query written with the ORM. This is --
JENS: You could now as a final step, and I think that's where we can then take it off. I think that's everything I wanted to show you. You could now use the graph again. And say, give me weather for the capital of the country. So, you can say... from the context graph.
JASON: Context, graph. From... we wanted --
JENS: And then you say query.
JASON: We want get city by name, I would assume.
JASON: Okay. And then we're getting where. Name is country, dot... okay. And then --
JENS: You need to say country.capital or empty string. Yep. And then we -- because we -- we don't select deeply nested objects by default. So, after dot query, you can add a dot select. And then you can pass strings for the path you want to select. So, in this case, you could say, for example, what do we have? We have icon. So, when you type icon, you would see the icon. And then you can pass a summary description, summary title. And you can pass these strings. It's just a periodic function.
JENS: And then it gives you back all these fields.
JASON: So, if I -- I just do three of these to get those three pieces.
JENS: Oh, I haven't tried that. But you can pass all of them into one select function. So, after select, you can have a comma.
JASON: Oh! You just add a comma. I get it.
JENS: Title and then description.
JASON: Okay. And there's the pieces. And now we've got our weather and then I want to return that weather directly.
JENS: Yes. And so, we can actually see the results. I think we could just use Postman, for example.
JASON: Okay. Sure. I can open up Postman again.
JENS: You need to re-load the collection. We talked to Postman team. And we asked them is there a way you can reload a election? Unfortunately that wasn't possible. You need to delete the collection and re-import it.
JASON: Got it. So, we will delete... and then import. And up in a finder again. Hopefully it's still in the -- it's not. Okay. That's fine. That's fine. We know how to get it back. It is the JSON API -- Open API.json. Reveal this one, Postman. And drop this in here. Okay. Then make this a little bit bigger. Here is our demo. Here is our custom. And I can -- oh, that one's just hard-coded. So, this will give us... here is our weather. And what we forgot to include is what the actual capital is. But that's okay!
JENS: We know that for Berlin, right?
JASON: Right. And so -- but this is -- I mean, this is really cool. You can see how quickly this all kind of comes together. And it's extremely cool that, you know, as we're doing these things, the part that I didn't call out as I was doing it is like these are all autocompleted. So, like if I want to get these things, I just hit, you know, control space. And it pulls up what the actual options are. And that's extremely cool. Like, it's very, very cool how quickly that stuff all comes together and gives you the ability to grab like a value. And, you know, this was all autocompleted. This was all autocompleted. The where was autocompleted. So, it's -- you can tell that this is a smart system that's kind of talking to the schema at every layer. And I think that's a very -- it's a very powerful way to work. There's a question from godavid. Is this only available in TypeScript? Are there other ways to use it?
JENS: Yeah. That's only available in TypeScript. And there's one thing I really want to point out that I think that's -- that's for me, that's the magic about this whole approach. And you can see layers building up on top of other layers. Because we have solved the problem of translating GraphQL to engine and now build the ORM on top. Now you can use this one ORM and talk to your SOAP API, to your REST API, to your GraphQL APIs and combine all the data into one request that serves your needs for one use case on the frontend for whatever you're building. And yeah, I think that's a very, very ergonomic way for engineers to work with data and to get something done. So, I -- I really like how this came together. And if you look at this code now, does it feel GraphQL-ish for you? Or how does it look like?
JASON: And this -- this doesn't feel GraphQL-ish to me. This feels, you know, like I've seen ORMs or data access SDKs look and feel.
JENS: Yeah. So, yeah. I think there's many other things we could show. But essentially, for me, that's -- that's really everything I wanted to get across. The idea of treating APIs like dependencies. And I think we've shown a couple of ways how you can do that here. And how you can make data integration easier. And yeah. I would love to see some -- some people trying it out. And if you have questions or anything, then we can have some more discussion.
JASON: Yeah. I think my -- the one thing that I did want to just point out because I think this is a really interesting and really important thing to call out here. Is that when you have a setup like this, where you're able to plug in any data source, you can pull in, you know, it's REST, it's SOAP, it's GraphQL, it's whatever. The -- the strength that gives you is that it allows for this really interesting incremental migration of tools. I think that a lot of times tools get built and sold in a way that is fully optimized for like a Greenfield rewrite. And if you look at the marketing of a lot of tech companies, they're effectively assuming that you have the ability and authority to just wholesale burn down and rewrite your entire app. And for any of us who work in companies of literally any size, the -- the feasibility of doing a full rewrite is practically zero. So, the thing that's really interesting about something like WunderGraph is if you have an intention of eventually rewriting your entire data layer, but you can't do it in one go, which is highly likely, by putting something into something like WunderGraph, what you get is the ability to swap out pieces without rewriting major frontend code. It's giving you -- we have this old SOAP API that we don't to want use anymore. We want to migrate it to REST with Open API. Okay. Great. Whether you do that, long as the API contract stays true, you can send whatever you want back and WunderGraph is going to return that data into the services consuming these APIs. You won't even notice that anything changed. And I think that's the sort of thing that -- that gets glossed over in a lot of the decisions about like how to choose tech. But like how painful is it gonna be to make a -- to make the change? Like after the fact? If you start adopting a piece of tech and then an underlying piece needs to change, how much does it hurt to make that switch? And, you know, my -- maybe this is my -- my crustiness as somebody who has been doing this for 20-plus years. But I am very much optimizing for the minimum amount of maintenance. I am not interested in building like an exciting solution that I'm gonna have to upgrade every 3 weeks because I'd rather be building features, something valuable for the company, the team, the product. I don't want to be on-call for fixing maintenance stuff because some thing doesn't work anymore. Now we have to go migrate millions of lines of code over to some new way because we switched tools. You want this stuff to be painless, you want this stuff to be incremental and you want it to be able to grow with you over time. And, you know, that's a very good thing. And so, anyways, that's a thing that came to me as I was looking at this. I was thinking about how much easier it would be with some of the projects I have done in the past rather than we to pull the brakes on everything, rewrite this entire app, oh, my god, we forgot some stuff, it's broken. Oh, my god, everybody is getting paged. We put this new data layer in place and incrementally fixing everything as things go on. And to everybody else, it's hidden and not necessarily to care about it at all. With that being said, Jens, where should people go if they want to learn more about WunderGraph?
JENS: Read the docs. Join our Discord, WunderGraph.com/discord. You can chat with us. We are very accessible people. If you deploy -- so, we also have WunderGraph cloud where you can one-click deploy and synchronize an app with your GitHub repository. And that deploys everything. We have previous -- everything you just saw, like you get analytics of your operation. We're currently building distributed tracing which I think is going to be super-huge because what you just saw with the ORM, imagine you make such a -- you call this TypeScript operation and you're using the ORM. And because the ORM actually calls into our virtual graph, we can instrument every API call with OpenTelemetry and we can give you a full trace of what actually happened and where it was slow and so on and so forth. You can see, again, layers and layers of value put on top of each other. Yeah, really just join the Discord. Read some of the docs. I would say I have an interesting blog. I'm quite opinionated about some of that stuff?
JASON: Ideal one find your blog?
JENS: I think there is a blog button.
JASON: This one?
JENS: Yep. One ORM to Map it All. You are invited to follow me on Twitter, Jensnoise_DE, that's my handle. Exactly. So, please follow me. If you're interested in keeping up with WunderGraph and yeah.
JASON: Great. All right, y'all, with that one, I think we're gonna call this one a resounding success. So, make sure you go check out WunderGraph. Check out go Jens. And thanks again to our captioner, we've had Amanda here all day from White Coat Captioning. Thank you very much. Through the support of Netlify, Nx, New Relic and Pluralsight all kicking in to make this show more accessible to more people. If your company is looking to sponsor this show, we're gonna have some scholarship slots open up soon. Please do let me know. Make sure you're checking out the schedule when you are checking out things on the Internet. Because we've got a great episode coming up on Thursday with Domitrius Clark, and so many great people I have not had the chance to put up on the website yet. Stay tuned. We have a cool new add to calendar feature so you can get notified whenever an episode is happening. It's not noisy. It's there on your calendar so you can see it. All right, Jens, thank you so much for spending time with us today. Thank you for hanging out. Let's find somebody to raid and we'll see you next time.
JENS: Thank you, Jason!
Closed captioning and more are made possible by our sponsors: