GraphQL - From Zero to Hero in 3 hours

Rate this content
Bookmark

How to build a fullstack GraphQL application (Postgres + NestJs + React) in the shortest time possible.


All beginnings are hard. Even harder than choosing the technology is often developing a suitable architecture. Especially when it comes to GraphQL.


In this workshop, you will get a variety of best practices that you would normally have to work through over a number of projects - all in just three hours.


If you've always wanted to participate in a hackathon to get something up and running in the shortest amount of time - then take an active part in this workshop, and participate in the thought processes of the trainer.

164 min
04 Jul, 2022

Video Summary and Transcription

Paweł Zawiecki, a software developer, shares his knowledge and practices in software development, focusing on Next.js, Node.js, and GraphQL. The Workshop involves building a social application called Micro Events using Postgres, Nest Shares, TypeORM, and GraphQL. The application utilizes Next.js with TypeScript for the frontend. The Workshop covers topics such as code generation, server-side rendering, entity management, and error handling. It also emphasizes the importance of understanding and working with Apollo Client in different contexts.

1. Introduction to Paweł Zawiecki

Short description:

My name is Paweł Zawiecki. I have a long career in software development, starting as a Java enterprise software engineer and transitioning to Full-Stack and mobile applications. I now prefer to work in startups.

So, my name is Paweł Zawiecki. I'm, as already mentioned, here located in Berlin. I live most of my life here in Germany. I'm working as a consultant, and also as a trainer. I have a long career in software development. I started as a traditional Java enterprise software engineer. But quickly, I realized, okay, it's nothing really for me. I prefer to work as a Full-Stack developer on different distributed systems, for example, and later on, I decided to move on into the space of mobile applications and front-end applications. I do it for a while, maybe for a couple of years, and now maybe for four or five years intensively in different projects. I started at some very large enterprise corporations here in Germany, IT systems, for example, and then I realized, okay, I really enjoy this small culture, the small culture of developers, where the developers drive the ideas, drive the technologies. So I prefer to work in startups.

2. Introduction to Workshop Topics

Short description:

I've written a lot of applications with Next.js, Node.js, and GraphQL as an API. I want to share my knowledge, patterns, and good practices with you. There are multiple ways to achieve the same results, but this is my approach that has proven successful in many applications.

Although, I've seen quite often the same stack, quite often in the background, some Java code, some Spring code, and in the front end, obviously, JavaScript, and so on and so on. Usually, it's the same technologies. It's unique how the teams work with these technologies. It's very unique, and I struggled a little bit to find the right path of how to do things with these technologies. Therefore, I think a good approach to start is actually to do some workshops, to do some workshops maybe with an advanced lecturer or maybe with someone who is already into this technology and shows someone the way to go. That's exactly what we'd like to do today. I've written a lot of applications with Next.js, a lot of applications with Node.js and the for example, a lot of applications with GraphQL as an API. And the most knowledge, this is something I'd like to share with you. Also some patterns, some design patterns on some good practices. I wouldn't say it's their way to go and you have to do things exactly like I show it. Obviously, there are a lot of ways to do the same things. It's just one approach. It's my approach, which already works in a lot of applications.

3. Introduction to Micro Events Application

Short description:

Today, we'll be doing some hard coding, like a hackathon. We'll be building a social application called micro events, where users can create and join spontaneous events. We'll use Postgres as the database, Nest Shares for the microservice API, TypeOR as the object relational mapper, and GraphQL to expose the API. On the frontend, we'll use Next.js with TypeScript for type safety.

So what do we want to do today here together? I decided instead of having some presentation for you or some theory, let's do some hard coding. All right. Some coding, like a hackathon. Let's decide what can we do in such... maybe three hours, maybe in two hours. Is it even possible to get applications up and running in such a short period of time?

So what we'd like to do today is this model of social applications named micro events, where everyone can... participants or the users of this application can create so-called micro events. You know maybe the idea of meetups, meetups are very well prepared. The name suggests meetups, but micro events are very spontaneous events created maybe right now. And users, which are interested in this event, can join this event and leave it, for example. Basically, that's it.

And from the technical perspective, we'd like to use Postgres, as persistent storage. So a traditional relational database. It also would like to use Nest Shares, for the microservice, actually for the API behind it, right? We'd like to use TypeOR as an object relational mapper. And we'd like to use GraphQL to expose our API to the public world. On the flouting side, we'd like to use Next.js with TypeScript. So we'll type a TypeScript template, because I think it's the way to go today, to be statically type safe, right? Type safe, right? So to avoid many errors on the run time, which can be avoided because we already have been on the build time.

4. Setting up the Application and Workspace

Short description:

Let's work together on this application. Use this repo as a starting point. We have a simple setup with Postgres and three projects. If you have Postgres running, you don't need the Docker setup. Follow the links for GraphQL and TypeORM setup. We use code-first approach for GraphQL and Postgres as the database. Look for entities and relations based on file names.

So I propose here to work together on this application. You can use this repo as a starting point. Let's go through this repo very quickly. We have a postgres Setup, you have an API, which is basically the Nest.js application, and we have a web application. The web application is the Next-based application. When you check this repository, or if you clone it on your local system, right? You can see the view, maybe like this, right? We have this README, this Code workspace. Actually, it's a file for your Visual Studio Code which creates a workspace with these three projects within it.

So, let's open it together. You do it so. Clone this application first. Start Visual Studio Code and open this workspace. Here it is. So, wait a moment. I said, let's create an application completely right from the beginning and we using a starting point as a typical Seed applications. Yeah, that's true. The reason for it. So, I already make some experiments with this workshop and with this setup, and basically it's quite easy. It's quite easy to show, but it's very time consuming. And sometimes we have maybe, let's say some minor errors inside it or we overlook something And we spent a lot of time just fixing this one little thing. So basically, it's a very simple setup. Let's go through it in a moment, but we'd like to use it as a starting point for our application. Whenever you have questions, please ask them. Just unmute, right? And ask them directly. If you'd like to follow, please clone this GitHub repo, code together with me. Maybe you have a different approach than I have. And please share it with us. So what do we have here when we start this application, when we start this workspace? As you can see, we have three projects inside it. API and Docker. The first thing is the Docker setup. Basically, it's just Postgres. Basically, it's just Postgres with initial user, micro events with initial password and the database. If you already have Postgres running, an instance, it's not necessary to use the Docker setup Just make notes on the user and the password and the database you're already using. In such, in this case, go piece to the API project to the AppModule.ts and here you see the setup for your Postgres. So basically it's the username, the password and the database, right, so just make it up and running this Postgres instance and make sure that it matches the configuration here in the AppModule.ts.

So, how to set up, actually, all of this? Right? We don't really go through this. It's very well documentated on the NestJS webpage and it's very well documented on the Next.js page how to create an initial setup. Let's just go through a couple of things which are crucial for this GraphQL setup and this TypeRam setup here. First of all, you have all the necessary links, right? So you go to the GraphQL page, you see what you usually have to do in order to enable a new NestJS application. Just GraphQL out of NestJS namespace. It's Apollo because we're using Apollo Server under the hood. We're using GraphQL as base model and we're using the Apollo Server Express bindings, right? Because in our case, we can go by default with this Express middleware for NestJS, instead of Fastify, for example. Basically, that's it. Some minor things still to do. If you go to your API application, again, to the App Module, here we are. Make sure you have graphQl enabled here for root, using the Apollo driver. And we'd like to have this schema file auto generated for us. As you might heard or not, NestJS allows us to work in two modes with graphQl. The first mode is code first. The second one is schema first. Here we decided to have the code as a single source of truth. So we don't really write the schema on ourself. Instead of it, we decided to let the code, the TypeScript codes, be the model we'd like to expose as a graphQl API. What's necessary to do for a typewrong? That's the second link in this Discord channel. Here we go. Basically, that's the type-in-arm integration. We have to install it in SjsTypeArm. Typearm obviously. Right? And then we decide what's our driver, what's our persistent storage, what's our relation to database system behind it. We're not going with MySQL. Instead of it, we're going with Postgres. So we have to use PG here instead of MySQL. Here, it's exactly the same setup as we see here in our application code base. Right? So, here we go. We're going with Postgres, localhost on the default port, and the already mentioned setup. Instead of deciding, okay, we'd like to put into this area all the entities we're creating one by one, we decided to how to look up for them, based on the naming of the file. All right? So, we decided, okay, let's look at all entities. Let's look for all relations in our code base. I have a TypeScript or JavaScript. Actually, this JavaScript doesn't really matter because we have here TypeScript only in this setup. And that's enough.

5. Snake Naming Strategy and Application Setup

Short description:

In this part, we discuss the snake naming strategy for mapping TypeScript classes to database tables in Postgres. We also explore the setup for developing the application and the use of debug terminals. Additionally, we show the running Postgres instance and the usage of a native client for better developer experience. Finally, we run the application in watch mode and explain how the schema is created and synchronized with the database.

Another package I already installed here is this snake naming strategies out of this time arm name strategies package. So, what is this? So, as you already know, type arm is an object relational member. This means we're writing TypeScript classes and like to map them to tables on our databases management system. But how to do it in terms of naming? Camel cased or upper case, lower case, snake cased, what's even possible?

So the traditional approach to do it in Postgres is to go with the snake naming strategy. So when you have something like foo bar written camel cased in your TypeScript code, it will become in lower case letters, foo minus bar as the table name. That's exactly what the naming strategy does. We also have a setup here, which allows us to develop our application quickly. We have a nice developer experience. So we are synchronizing it directly and we are dropping build schema every time we are restarting the application. So from time to time, it might be important because things go wrong when we develop. So we decide maybe to kill our application to kill our API, restart it and have hopefully an initial clean setup in the database. So that's the drop schema actually, the property here, in this case. So that's it here in the API.

One thing I forgot to mention is how to work actually in this Visual Studio Code. How to make things easy for us and good approaches to open a couple of terminals for us. Let me do it for the beginning. For example, when I start with the API here, right? I go maybe to the web application. And then I decide to open, I decide to open the debug terminal of an API application. Let's rename those two terminals. So the first one is the web application. The second one is the API. Why do we have this API as a debug terminal and the web application as a, let's say, traditional terminal? Because the debug terminal allows us to start the scripts running here out of this terminal in debug mode. Actually, we connect our IDE to our runtime. So that it allows us to set breakpoints in our application. That's not the way we are debugging in the front end. Usually in the front end we hope to have some source mappings so that we can debug this application directly, let's say, in the Chrome Developer Tools. So no need to open a debug terminal here. So let me show you my application, my Postgres running. So I have this Postgres running here as a Docker container. Here it is. Right. It's already up and running. You can decide to use pgadmin, for example, to access or to check or debug Postgres. I prefer on my Mac to use a native client, which is postdeco, for example. It's a free tool, but it gives us a better developer experience. For example, as you can see, we already have two entities inside it. You can see we have the schema definition, the structure, in a visual way, and the content as well. The same applies here for the foo, for example. As you can see, we already have one data set here, and we can actually update it directly here. So this tool is what I'd like to use in this small workshop. So Postgres is running. Let's check if we have installed all the required packages. Cool. Everything works, so let's run it. First of all, it always makes sense to check the package.json, obviously. You have required scripts here or preconfigured scripts. I decide to use the StartDev because it's exactly doing what I'd like to have it running in the watch mode. You can also use debug, for example, with some additional debug logging messages. So basically, this debug command is setting up a node environment with the debug option set to true, which usually enables our application to print more verbose console logs, for example, or logging messages in general.

We are here in the micro-servers, micro-events API application here, and when you run yarn start dev, let's do it. You've seen for a while, debugger attached. So no errors. And you can see a lot of logging messages which are somehow related to my database, as you can imagine. Some transactions start here and we can do some checks if actually everything is up to date, for example, when we start a transaction. And within this transaction, we create that schema for us. Office type font is creating the schema for us. That's basically what is set up here in the app module, right? Synchronize true. That's a good approach because our application is running in the watch mode whenever we add, for example, a new entity to our application. So a new class which actually represents a table in our database or should represent a data in our database. This change is immediately synchronized with a database management system, our database actually in Postgres, and so that's asynchronized. It's a very nice development experience here. As you can see, this application starts in debug mode. Very neat way to debug things or find errors in our application as soon as possible. Let me give a short example for this. Maybe we have here this app controller. Here we have this gethello operation. Let's put it here, and start on localhost default.

6. Introduction to NestJS and Web Application Setup

Short description:

NestJS is a framework built on top of existing and well-known libraries in the Node.js world, like Express. It introduces good practices and is built around concepts from other frameworks like Spring Boot and Angular. It has a CLI for creating code artifacts and a well-working debugger. The web application uses Next.js with TypeScript templates and Apollo client. The GraphQL Playground is included, but can be disabled if desired.

Maybe we have here this app controller. Here we have this gethello operation. Let's put it here, and start on localhost default. Sorry, Paulo. I've never used NestJS and I'm getting the Nest command not found. What's the library called exactly? NestJS? Exactly. Let's go to the steps, step by step. Usually, in order to set up something, let's make a short demo. TMP, and then set this TMP. Let's create a short application. Nest. Let's name it foo. This will create a new Nest application for us. Here, you choose this node package manager you'd like to use, maybe Yarn, if you'd like to stick to the same as we're usually using in Biryatwork. This would, well, actually this should set up a complete Nest application for us. But while it's installing, a brief history to Nest.js, basically Nest is a framework which is built on top of existing and well-known libraries in the world, in the node which existed in the node world forever, like Express, for example, for creating RESTful APIs, usually you use Express, or one way to do it is to use Express in the node.js world. But it also introduces a lot of good practices inside the world of Node.js, for example, starting with the programming language itself, like we'd like to use static type-checking with TypeScript, for example. So we don't have to deal with this issue to set TypeScript on our own and business back-end world here. And also, it's also a little bit built around the ideas we know from different frameworks in the back-end world, like, let's say Spring-Wood, maybe of a Java enterprise deck, and also on Angular, for example. So, if you're using Angular and the front-end, you know you've seen quite a lot of concepts which are almost the same here in the NestJS world, for example, dependency injection, modules, components instead of components we have the so-called controllers here and services, which are also injectors. But we'd like to go through this details step by step when we focus on API instead. But basically NestJS is, let's say, something on top of existing and well-known libraries like Express, Passport with a very neat setup, TypeScript, for example, is built around, with best practices in mind, with a very well-working CLI, so a common client interface, which you can use to create artifacts, code artifacts, in your application, and so on, and so on. But we focus on it a little bit later. So, let's go back to a NestJS project.

So, as you can see, I have executed or I asked for localhost 3000 here, right? And somehow I ran into this breakpoint. And here I can debug certain things, maybe, right? So, as you can see in this, so, basically the instance of this app service I'm looking through, I can see what's actually inside it. So far, nothing special. And I can debug step by step, usually using my Visual Studio Code itself. No need to have console locks or things like that. It can be done directly in the IDE. Let's move the breakpoint.

So, I have my application up and running. There is a special—as you can see this hello world— there is a special end point I'd like to show you here. It's GraphQL. Wow, what is this? This is actually something named Playground. It comes with this NestJS GraphQL package. You installed this application, this full loaded web application inside your endpoint by using this NestJS GraphQL module. Just to remember it, or to recap it. Let's take a look. Here it is. Typeform-GraphQL-Module-for-root. Here you set up this GraphQL module. And you can disable this playground using this playground property. If you don't like to have it for some reason, just set it to false. Usually, that's exactly what I do. You can do also this kind of setups to set up this properties, this host name for it, and this configuration. You're using environment files, configuration files which might be based on your environment, or environment variables, for example. For us, let's keep it simple. Let's hardcode our setup, our configuration here. Okay, here we go. As you can see, whenever I make some changes to the code, it's built automatically. Because we have a watcher running on it. I guess you know this developer experience already from React, from Angular, and other frontend-related frameworks, right? Where you usually have this development server within which Watchmode is running. Okay, next thing to focus on is the web application. So let's close API, and let's go to web. This is a typical next.js setup with the TypeScript templates, right? It's created as already, let's put it here in the chat Discord channel. How do we join the Discord channel? I don't see the... I don't see JS workshops. RS-workshops. Maybe I send a direct link somehow. Copy link, maybe this works. Give it a try, it works for you. Yeah, as well. So no need for you to create this application right now, right? So that's what I already did for you, right? I think npx create-next-step, I use the latest version, a minus, minus ts, which says, okay, let's use a TypeScript setup and I'd like to name my application micro-events minus web. That's what I already did for you with some basic limitations, with some basic configurations. Let's go through this basic configuration. Those are a little bit more important than what we've seen in the API because most configurations we've seen in the API module are well-documentated directly on the NestJS documentation pages. But this here we have to go through a little bit, right? That was one of the reasons why I prepared this application beforehand, before this workshop. So basically we installed the Apollo client, right? So let's check the package.json, and we have this dependency to Apollo client. And that's one, that's very important, we'd like to use.

7. Apollo Client Setup for Next.js

Short description:

To consume GraphQL based APIs in a Next.js application, we need to install the Apollo Client and wrap our components in an Apollo provider. The provider requires a client parameter, which we create in a separate folder. The client is created with an HTTP link and can be customized with additional features like multi-part uploads. We also specify the caching type. This setup is specifically for the front-end part.

And also, we'd like to have this type definition for us, using all the types. For example, Types, GraphQL, or Types, Apollo Upload Client. Well, one thing worth to mention, I also have this upload client here. Something we want to really use in this workshop here, that's one way for creating uploads using GraphQL. Usually, it's not handled by Apollo direct. It's an external package of having this multi-part uploads, right? So usually, we don't have them enabled by default.

All right, so two additional packages. First, we have Apollo clients and Apollo upload clients. I would also like to share. It is the required setup, if you'd like to do it using Yarn. We use the... Oh, sorry, that's the wrong one. That's the wrong one. Not the correct one. The correct should be Apollo clients. Sorry for this confusion. Yarn, add, Apollo clients. That's the correct one. That's what we need. No need for type definition files because this Apollo client already comes with type definition files enabled to it. Okay.

Something from Kassim. Mine redirects to FUSE on start, but I can't navigate to GraphQL. Okay. Let's go to a set up in a minute. Right. Because, before we completed this configuration part here. So what is actually necessary in order to consume GraphQL based APIs in front end? Especially in the Next.js application? First of all, we have to install this Apollo Client. And the second thing we have to do, is to go to app.tsx. Here it is. Right. In a package folder, we have this underscore, app.tsx. So the base starting point of our application.

Well, actually all the screens we're using, run through this my-app component. We going to be wrapped into this my-app component. This allows us, to add some provider around the required fashion component, right? This is for example our particular view or particular page we'd like to render the components and this comes here using this app props. And we pass through all the page props that we need to somehow remove them or somehow to edit them or from time to time we need them to make some modification to configure our provider somehow. Sometime it's based on the props but in most cases we don't really use them. So we just pass it to the component. But the crucial point here to do is to wrap all this into this Apollo provider. This Apollo provider asks us for one parameter. This one parameter is the client itself. So we have to create an Apollo client. All this magic, all the hooks, for example, we take later on to use, for example, we use Query or I use, use mutation hooks, for example, work somehow with this client under the hood. All right. So first of all, let's create such a client. Therefore, I create an additional folder for us with some common settings. Some common settings. Usually it's not so complicated like this. But I added this file. It's a little bit more of both modes for you to show you some things. So basically in the end, we'd like to create an Apollo client within a link. This is basically a data link. A data link of a protocol you're communicating through. Either usually HTTP or HTTPS. But somehow you have some additional features added to it. Maybe authentication. Maybe you'd like to work together with NextOut. So some very fancy module, for example, for a Next.js to enable all this token-based authentication things. Maybe you'd like to also somehow interfere with this traditional link, or already existing link. For example, extracting multi-part uploads. If you like to use, for example, this upload feature as already shown here, create upload link. Use this create upload link, instead of this already pre-configured, pre-existing HTTP link out of the Apollo client. So we use Apollo upload client, which is basically the same as the existing HTTP link, but it uses some additional features, like extracting multi-part uploads. So we've created this HTTP link, and with it, we use it. Here, we also decide which type of caching we'd like to use. And as you can see, we somehow, sometimes can use this, sorry, where is it? Where exactly is it? Sometimes we use an already created constant here, this Apollo client. That's what we do with using this provider. But this is for the front-end part.

8. Frontend Setup and Configuration

Short description:

Next.js allows us to render pages on the server on demand, but sometimes also statically. For pre-configured pages, we use server-side rendering, otherwise, static site rendering is used. The Apollo Client is used for accessing the GraphQL API in the client-side application. For server-side and static site rendering, a custom Apollo Client is created on the server. The basic setup is done using the apolloClientWithToken function. The application is already running, and we can start the frontend using the 'yarn dev' command. The 'next.config.js' file in Next.js allows for pre-configuring redirects and defining features for different URLs. The Apollo Client DevTools plugin for Chrome is recommended for debugging. The Altair tool is suggested for writing queries with auto-completion.

But this is for the front-end part. As you maybe already heard, we usually use Next.js to decide where we render things. Either in the client, so in the web application itself, in the browser, this is the traditional way. But this way, as you maybe already know from Create React app almost everything, all the action happens in the front-end in the web application, in the browser itself.

But sometimes, we'd like to use something like server-side rendering, and we decide to render pages on demand whenever they are requested. Imagine you're building an application like Amazon, where you can buy multiple books, for example, and you'd like to share very specific books identified by a given resource identifier, the URL usually. And you send this URL to a friend, for example, maybe using Discord, and what you see here in the Discord channel, you see a small preview of a book. So how does this magic works actually? So that Discord knows which picture or which preview title of preview description of this book to show.

Usually you use something like OpenGraph, which is based on meta text. So meta text are some special HTML text, which you enable in the document to be delivered. So it's not possible, it is possible but it doesn't make sense to add meta text dynamically whenever the application is already delivered to the client. Instead of it, when I send here link to a very specific book on Amazon, it's a rep crawler, an agent of Discord. Scraps, but a document behind this URL looks for this specific meta text, extracts the information's inside this meta text and shows the information here as a small preview. So for such techniques, we usually have a need for maybe server-side rendering. To deliver already a preview for a pre-rendered document with this meta text, which are very specific to the book shown. So Next.js exactly allows us to do such things like rendering pages on the server on demand, but sometimes also statically. So usually we render pages on demand, which are based on maybe ID, which is somehow encoded in the URL. So as you can imagine, you could have an endpoint slash books slash ISBN, which already identifies the books. For such scenarios, it makes pretty much sense to do it on demand, but on the server, to have this meta text enabled. But sometimes it's time to type, like maybe the homepage or the start page of our applications, which is always the same, not really based on any inputs, not really on any URL or query parameters. It makes sense to pre-render all of this on build time. In this case, we talk about static site rendering. So we have this one, the default option is to render on the client itself. The second thing, which my expert pretty much says, is for pre-configured pages, like maybe dynamically created pages on demand, then we use server-side rendering, otherwise it might make sense to have some static site rendering done based on static resources. That's what we have Next.js for, and this client, as provided here, is for this front-end use cases only. So whenever the application is already delivered to the client, the web browser, and it's already running in the web browser, and we would like to access the GraphQL API from the application running in your browser, then under the hood, this Apollo Client is used. For all the other reasons, server-side trending, static-side trending, you have to create your own Apollo Client, which is executed on the server, so in the node.js environment, basically. Therefore, we'd like to also use heaven function to create such clients dynamically, maybe on the server side. Whenever we need it, use this function, apolloClientWithToken, to create such Apollo Clients. So that's the basic setup I already did. And let's see some magic. Okay. We have this API already running. Let's start with frontend. Yarn, dev. Right? And now, let's take a look in the package JSON. The scripts area, aha. Dev, next dev. Makes pretty much sense for us. So let's start it. Okay. All active foos. So for now, we don't have any foos. Right? So we see the page. We've got also a redirection. Open local host 3001. And I've got redirected to foos. So where does this foos comes from? Actually, there is a configuration file in next. Next config JS. Right? In this next.js config, you can pre-configure some redirects. That's a good practice. Instead of having a default resources with traditional home component, for example, it makes pretty much sense to think in features. Right? So have a dedicated URL for each feature in your application, and make the decision for the user. Which is the... What feature is the first one, which should be entered when the uses chooses to go with with the empty route. Sorry, with an empty path, in such scenarios. So whenever a user calls the empty path, our scenario, it likes to access the for-feature. Okay? So... All things are already working. I recommend a very nice plugin for extension actually for Chrome, which is the Apollo Client DevTools. So it's located here. And like I entered, whereas this page, clefoos, those two queries have been executed. MoreElectiveFoos as defined here. With no results. Oh, sorry. It's defined, but no results in our scenario. So why not? So let's talk about the API first, all right? So let's go back to application and see how it behaves. So I recommend to use a more sophisticated client instead of this playground, which is Altair. It's an open source tool and one of the best features of this tool is auto-completion. So whenever you write your queries, you don't have to type them manually.

9. Creating Queries and Mutations

Short description:

We select queries based on the schema. There are two existing queries: Foos and foo. A foo is an entity with an ID, live property, text, and a relation to bar. We can create a query to access the collection of foos and a specific foo. Let's execute the query and create a foo with the Apollo Client.

Instead you just select based on the schema. You select the queries based on the schema. So I already did two of them. Oh, I created all three, sorry. Three queries.

The first one is all foos. Let me execute it. As you can see, I get no results so far. So let's recreate this all foos query again. I start by entering the schema file, which is localhost 3000 graphqm. I make sure I always have the latest version of it. And here on the right side, I've got the documentation for the schema divided on the two categories, query and mutation. So let's see which queries are actually already existing on API. Foos and foo. Foo is for accessing the collection of foos. And foo is for accessing a very particular foo. So what is a foo? A foo is basically an entity with an ID, with a very fancy live property, a text which is a string, and a relation to bar. So we have foo and bar in our application. And bar is something which also has an ID, a live attribute, a text, and a relation to the parent foo. So that's basically a foo. Let's go back and create this query. Add query. Here we go. Let's decide from the bars, all we want to access ID and text. Let's execute it. That's exactly the result 87 milliseconds ago. So, I've got the current one. Okay, no data so far. Let's create a foo. Oh, we are slider on that. Oh, I am. Oh, we are solving on that. Name of the client is Apollo Client. Okay. So we have probably somewhere on an break point or something. Let me check. First, what's the issue right now? Okay, no, it's not. So I'm not sure why it's, this is still working. Oh, here we go. Here we go. We already have some data inside it. So probably the database was not set up correctly. Already have some data inside it. So let's run it again. So here we had, what is going on? Something has happened. I think here is our GetFoos. Let's run it again. Get all foos. It's a query. Right, so let's execute it once again. Okay, empty dataset. I guess I had an old window opened. So now everything is fine. So let's create a foo. Let's go to another window. Go to the Docs to the mutation. And say we'd like to choose CreateFoo. Add query. Here is the mutation. Let's give it a name. CreateFoo maybe. And this CreateFoo, requires us to pass a CreateFoo input. Which is basically a text and a Bars array. And each particular Bar out of this Bar array has a text field. So let's pass this. First of all, let's start with the text. Let's give it a parameter first. So CreateFoo gets the text. Those things, which is a string, which is required. Next string, we'd like to have the Bars array.

10. Managing and Optimizing GraphQL API

Short description:

We execute a mutation to create a foo with the given variables. The API returns the created foo object, including the ID, text, and relation to bars. We can also access the created foo in the foos collection. To work with the GraphQL API in our Next.js application, we create a dedicated folder for queries. We define constants for the queries using the gql template string. However, the useQuery and useMutation hooks return data in a general way, so we need type definitions for the query results. The Apollo client provides tools for auto-generating type definitions based on the schema and queries. We can download the schema from the endpoint and generate the type definitions using preconfigured scripts.

It just have type CreateBarInput. I'm not entirely correct. It's actually an array of CreateBarInput. Each CreateBarInput is required, not optional, and also the Bars array is required. Let's pass this text variable here inside this input. Text, here we go, an arrow and bars, we'd like to parse here. Yeah, that's also the same mistake. Let's decide what should be the result of this mutation. I suggest to keep it simple, so don't test too much. So from the bars, we'd like to get ID and text only as result.

So next thing, in order to create such a fool, we'd like to execute this mutation with values for these variables. Therefore we use these variables here. Let's give it an example. For text, we'd like the same. Super. For bars, we'd like to give an array. Each array is actually a create bar input, which asks for a text. Let's say, hello. Let's have another one. It is hello. Okay. Workshop. So let's execute this just created mutation with this variables. Here is four, four of this inputs of this mutation.

Whoa, we've got results. So the idea has been created for us. The life object. When this object has been created and the last updates timestamp are created for us on our API, so what's not in our control it's something done on the API side and deactivated at is on now because this is active object. We just created foo. But you can see also that text field here on this foo and then relation to the paths. They've always asked values. So our API is working. When we go back to our foos as executed it got also the same database. So what can we do with such API? How to access it from this Next.js application? In order to work with it with a great developer experience here, I created a GraphQL folder with the queries. So a dedicated folder just for obviously queries we already have. Let's see the examples.

All right, so just a constant here, all-active foos. And I use this tech, a GraphQL, found with Apollo Client, which takes a template string with our query inside it. So basically the workflow is to try some queries here, copy paste this query. All right, copy it. If we feel sure that that's exactly what we need, we copy it here and paste it here inside the string, for this GraphQL tech. We save all this in the constant, all active foos in our case. I did the same already for create foo. So creating one. That's exactly what you've seen so far. And for find foo by ID. So later on, I'd like to use this queries and this mutations, whatever it might be. So I have a queries as shown here or mutations. I'd like to use it inside my react app using the use query and the use mutation hook.

Okay, but there is an issue. With this use query and this use mutation hook. They are written in a very general way. So basically, they return some data, but what is data and what type is data? All right, because in JavaScript we have duck typing, so we don't really care about this information, what is the type of the data, but here in TypeScript context, we usually care about it and we'd like to have a great developer experience using, let's say IntelliSense, accessing certain fields of the results of this query and so on, therefore, we need type definitions for the results of this queries.

As you know, as you see, it's a little bit different as in traditional REST APIs, usually when you use REST APIs, you know this call returns exactly this result of this type, so you can give this result a type, you can hardcode in your application, you could say it's get all active footh response or something, right, and program your interface, but it's not possible to do it in a very general way in GraphQL to model this response object with domain objects because the type depends on the request itself. You can have multiples create foo operations, or mutations, sorry, which return a little bit different results based on McFerry itself or the mutations itself. So it doesn't really make sense to introduce here in our front end application a foo interface because we don't really returning a foo here as a result of this create foo mutation or the active foos. It really depends. For example, I could decide to say, okay, I don't really care for this process here. I don't really care for ID. Right? And so for this very particular query I need another type as a result for the use query hook to be used.

So how to do it? The worst thing to do it, is the worst approach to it is manually. But luckily as we are, the Apollo client or the Apollo projects gives us already the necessary tools for it. They're well-documented and all this is just code generation. So basically by looking on the source code, looking for all this GQL text, so based on this GQL text we'd like to generate auto-generate based on a schema as one input and on our query as a second input, we'd like to auto-generate type definitions. So... Therefore I also already preconfigured for you two additional scripts. And so usually you don't have to really code hard coded into this script area of your application, you can memorize it somehow or write a shell script to simplify your work. Basically the idea is to download a schema from the end point, the last recent one. So when already running active schema we'd like to download it, right? Let's do it under the name, GraphQL schema. Let's download it, that's exactly up the portal, service download from this particular end point.

11. Code Generation and Accessing Data

Short description:

We execute a script for code generation in TypeScript using the Apollo command line tool. The generated code is based on the queries in the GQL folder. We ensure that our GraphQL API is running before running the code generation script. The generated code includes types for the queries, and we can access the data using the useQuery hook in our Next.js application. We pass the query and variables to the hook and destructure the data to access the required information. We can customize the variables and handle loading states in our application.

Another script you'd like to create is code generation. All right so first of all we execute here in this GQL code generation, this download script. So we are very sure we already have the most recent schema file in our source code here of a front end. Then we use again, the Apollo clients of our Apollo tool, command line tool. But in this case, we use code gen, generate with from now a local schema, which we already downloaded. So we'd like to generate code for TypeScript. It's very important to say it here that it's TypeScript because it's Apollo, Apollo command line tool works for Swift, for example, for iOS files or for Android generating content files, for example, and so on. So it's a very general tool, but we are working in TypeScript environments. So we'd like to generate TypeScript code. We'd like to consider as an input for code generation, everything which is located in the GQL folder and it has a TypeScript suffix. And we'd like to do it based on the GQL tag. So obviously no code, which is usually to be memorized instead of reliant documentation of a Apollo project, right? This is very well-documented how to generate code based on a schema tag and based on our existing code. So let's run it. The first things we have to make sure is that our API, our GraphQL API is already running. So let's take a look if it's the case. Yes, it is running. So it's a running project. Then we switch to a web project again. Let's kill it for now. Let's run. Yarn GQL CodeGallery, so GQL CodeGallery. So as you can see, it's already downloading your files and it's auto generating TypeScript based on our queries. So let's take a look into the generated files. No, no really need for it to do it so, but just to give you a brief idea, for example, for this all active foos, all right, we've got a lot of types. The starting point is here. AllactiveFoos, which has this foos array, all right, which is of this type. And we ask for this fields for each foo. All right, so for example, the bars, is given here, that's exactly what we asked for. So we can't really, cannot really introduce a general bar interface here, we have to rely on BigQuery itself because this query asks just for these two fields, using code generation here. And that's the way to go. So, let's take a brief look on how to actually access this data. You will have a page, right, as you may already, might heard of, maybe in another workshop or you already had some experience with Next.js. You know this pages folder and GraphQL, sorry, Next.js has a very specific role. So everything which is located here under this pages folder is directly reflected to our URL or to the path, actually, which the user puts into the browser. So we're accessing here, this foo's path, and inside this foo's we have this indexed file, which is basically the localhost 3000 slash foos, we are addressing this indexed.js here. So let's take a look on this foos. We have this all foos page, which is a traditional Next page, and here we use this useQuery hook. All right, useQuery hook, it's a generic hook. So we have to pass the datatypes as generated for us. So our active foos is exactly what we are asking for, the types of the variables, and then as a parameter to this query, we pass the query itself, right? So here we go. That's the query we pass in this parameter. Okay. Sorry. So let's go back to Index. Here we have variables. If with all active foos asked for certain variables, can pass them here using IntelliSense, like skip or take. Let's take a look on our all active foos again. All right, all active foos, in our case uses the skip and the take perimeter, which is past the ferry itself. It's a range property. We haven't seen those properties before, but because this one, what I already hard-coded here into this seed projects, this differs a little bit from what we created here together. And so here we have some additional properties, right? Some of the common property. And for the common property, we said we'd like to only have active foos. We'd like to ask for foos and because it's returns a large, potentially a large array, we'd like to skip some of them and take only maybe 10, right, to work on a such, let's say pagination use case. So that's exactly the parameters which can be passed through this query. Right, so I can also skip, use it until it sends. Say come on, I'm interested in having 10 foos. Right? The use query will return an object with a lot of data or a lot of properties inside it. But for most use cases, to be honest, only three are really important. It's the data itself. So it's all, we're using the structuring usually. Right, so we like to access the data. Let's give it, this data a meaningful alias name or active foos for example, a loading flag which indicates if this operation is still running, it's a boolean, right? And an arrow flag, which has the arrow in an arrow case. But I haven't used it in my presentation. So as you can see here, right? First of all, relying on this loading field, I'm saying okay, in case if this is loading, it's saying loading. And what, otherwise, we're assuming all active foos, foos, has some data net. Let's make each of these foos add to some to a foo and displayed some basic information for each foo, maybe the idea itself. Making an example, hopefully, our application will show something right now because we already created in our API. Let's make it sure that we already have some data inside it. So again, all foos, let's execute it again. So we should have one foo inside it.

12. Server-Side Rendering and Apollo Client Setup

Short description:

In this part, we discuss server-side rendering on demand using the GetServerSideProps function in Next.js. We create a client on the server using the Apollo ClientWithToken utility and run queries using the client.query function. The result is passed as a prop to the foo page. Charles mentions an issue with Apollo not being found when running the GQL scripts, and the speaker realizes a missing dependency in the package JSON.

And so application is running, let's go again. Foos, here it is. Okay, next thing we should know, we should know the food score. So, let's go back. So my team is data survivor. And our number will be one. Foods, none of them. Wow, so that's some interesting data about the foods as you can remember food has a text property and this is rendered here. The idea is in the text. But the implementation is a little bit different. So let's take a look on this first. Let's take a look on this first.

Here, I'd like to show you another technique. So, let's assume I'd like to share this foo with you. Maybe in the score. In our case, we won't really render anything fancy, we won't render anything at all, because I haven't configured it so far. But what happens actually here when I share this link with it, whoever wants to see this document behind this URL gets a view for a very specific foo. And this view is already created on the server for you on demand, right? On demand. So it means, okay. If it's the first time I share a URL like this with this hard coded UUID inside it, this page is created on the server for you with potential some meta tags which show up in a very nice preview here in discourse, for example. So the technique here is server-side rendering on demand, obviously. The way to do it is to provide inside the page tsx file a GetServerSideProps function. So we're exporting two things here inside this id-tsx. The first thing we're exporting is the foo page itself, so here it is. As you can see we're rendering the foo id in the text, so that's exactly what we've seen. And we are expecting a foo parameter for this foo page. And this foo parameters of type foo, which is just a type area of this very specific and auto generated type. Because it depends on the query. So that's what I actually like to pass this foo page here, as a parameter. And I like to do it on demand on the server, therefore I provide a second export, which is the get server-side props. It's an async operation, based on the context. The context, I can use the context in order to access the parents. Right, I can use context parents in order to access the idea. The idea is here hard-coded as an information into the document, into the source file itself. That's the way how Next.js works, right? So this parameter information are hard-coded inside this, the filename itself. I'd like to access this ID and I'd like to treat it as a string. So, what I've been doing here is to create a client. Why don't I use the useQuery hook here? Because this code is executed in the back end. It's executed on the server. It's executed as a Node.js script in a Node.js environment. It's not executed in the browser. It's also not executed in the React context, which runs in the browser. So it's basically, it just a usual traditional function, let's say, name it like this, which is executed on the server. That's how Next.js works. Whenever it finds this GetServerSideProps function within such a page file, this function is executed with this context of this Next.js application. Therefore, I have to use the second utility, Apollo ClientWithToken. That's exactly this function I have shown you before. One of these possibilities to create such an Apollo Client whenever I need it. So it's another one. It's not the same Apollo Client as provided using this Apollo provider. So let me show it once again. So we've seen this Apollo provider and we passed already Apollo Client inside it. But this Apollo Client which I like to use in this function as shown, which just shown it's another one. This one is always used in within the hooks in the frontend, but I'm recreating one on demand on the server within this get server-side props here and use a somehow similar approach to run queries. I use directly have client.query also passing the very specific query I'd like to use, right? To the auto-generate types here and with this query here, find-foo by ID passing a variable. Since, as you can see, the code somehow similar as to the query. Use query, I'd like to access this data and the foo to get this foo out of it. And I like to have this foo as a prop as to be passed as a prop to the foo page. So with theory, receive this foo.

Okay, Charles says, I must have missed something. I am seeing Apollo not found when running the GQL scripts, not seeing Apollo and node modules. Yeah, I know you mentioned this a while ago. I was just trying to debug it while you were going through the other things. We're installing Apollo globally. When I do that, I'm seeing GraphQL, certain GraphQL validation is missing, but I'll do it again. I tried installing globally and then I'll let you know what the error is exactly in a second after I do this. Okay, cool. Actually, that's something I forgot to mention. So probably I'm missing here a dependency in the package JSON.

13. Dependency Installation and Code Generation

Short description:

I'm missing a dependency in the package JSON. I installed Apollo globally but cannot find the necessary module. The solution may be to install the missing dependency. This approach to code generation may change in future versions of Apollo. Apollo can also generate Swift files for native iOS applications.

So probably I'm missing here a dependency in the package JSON. Probably is. So I've installed Apollo globally and I cannot find module GraphQL slash validation slash rules, slash known argument names rule. This is when running GQL download schema. That's also necessary to have this GQL, sorry, this specific version. I do have three, five, six in my package JSON, having not changed a lot aside from installing. And maybe, do you want to share your screen with us? Sure. I should change my resolution before doing that because it's quite a large screen. So give me one minute, 30 seconds. Okay. Okay, let me know when you can see this. Okay. This is what I was saying, just installed the Power Boy. Should we be on any specific version? Oh, I've seen this before. I've seen this before. Not sure what the solution was I think. Yes. I ran it on your install. Yes. Node version 16. Someone's asking questions in chat. I was just answering. Hmm. So to be honest. I don't wanna hold everyone up. It's okay. I'll just follow along and see if I can trigger a sub. Yeah. But I think the solution was to somehow install exactly this dependency, which is missing. Yeah. Okay. I've seen this before. And yeah, also the graph QL version. We have probably are you saying I'm sorry, you said globally? Yes, globally because you're running. Yeah. Because you ran okay. Maybe you draft QL right? Yeah, maybe. Maybe all right. I don't wanna hold this up. So, okay, great. We'll say something else. Okay, cool. Thank you. So you should see my screen again. Okay, cool. So, by the way, by the way, this year with this downloading and this code generation and so on. It's a traditional approach which was for a while, right? Maybe for one year, I'm very successful with this code. And that's exactly the code as documented on Apollo projects. But they already mentioned that that's a candidate to change. So all this code generations such a cool thing that they actually like to somehow simplify all of this. So this is actually a candidate to change the future versions of the Apollo. This approach how to work this code and generate as well. By the way, I also have unsuccessful set up for Swift, for example. If you're developing, for example, native iOS applications, it out generates Swift files for you or Swift types for you as well. So it's a really cool project by the way.

14. Server-Side Props and API Code

Short description:

Let's move on to server-side props and caching mechanisms. When accessing the GraphQL API on the server, no queries are shown in the React context. In the API code, we have a foo module with providers and services. The public object is an abstract class that represents entities exposed to the public, with commonalities like an ID and timestamps. TypeORM handles the auto-filling of timestamps. Deletion of instances in a relational database can cause problems.

Okay, let's move on. So again, as we seen, another way you get server side props to let this piece of code running on the server on demand, whenever a new URL is accessed. Basically it's some caching mechanism involved. So not every time this path is executed, this function runs basically also the outcome of this service like rendered document is cached with the time to live, it's kind of performance. If you'd like to do it on the client side, again, you just access the ID itself, which comes directly, sorry, you use ID for example, I just use traditionally we use query on the front end.

One thing worth to mention, if you do it on the server side, accessing the GraphQL API on the server, you won't see anything here. You won't see anything here or active queries, not no queries at all, because what we see here are the queries in the front end application in the React context. So we, Apollo client is provided by the Apollo client provider. And but here we execute the query on the server on demand. So no queries shown here. Okay, cool.

I think basically, that's the first part of this workshop. I told you somehow, F is code up and running, get some basic understanding, what's actually going on in the front end. From now on, we'd like to implement our very simple micro events applications. So basically, we'd like to extend our GraphQL schema on the API side. And we'd like to introduce some queries in order to access all the micro events. We'd like to introduce a mutation for creating micro service. And we also need to do some work on the API as well. Actually one thing I forgot to do with you so far to take a look on the API code. So a backend code behind it. So let's do it first before we go to micro events application. So on the API, on project here, we have a foo module. All right, so each module in an sj applications has a module file. You're just export class foo module, that's a TypeScript decorator with exactly one parameter. And this one perimeter is an object literal or an object general with some setups. And some key values, right? So usually the key is on the left side, of course, and over the right side we have usually the value given as an array. Not always, but in most cases for most keys, most are arrays. Here we have some providers. Providers right here, I don't want to be talked about the dependency injection in general, but basically we have this inversion of control approach.

So the NestJS application is a running application, a running container without your code, without your actually code artifacts, given it already runs, but you provide some code artifacts by fulfilling a kind of contracts. And NestJS, whenever it sees some of your... when it sees some of your provider artifacts, maybe your full service, at a given moment on time it creates an instance for you, it provides all the dependencies for you. So basically, the instance of this full service is an object, a so-called managed object which is maintained by the framework and not by yourself. So you're not creating full service instances on your own but NestJS is doing it for them. I don't really go too deep into the idea of dependency injection. Basically, we need to fill a complete workshop with it to get some understanding for it. But the way how it works is that we have this one module for this full feature with some code artifacts inside it. NestJS has this very fancy naming convention here in that finance. You see.reserver TS,.service TS,.module TS. Technically, those are all classes, right? TypeScript classes. But in order to get some understanding what role this class has in your application, we give them stereotypes to identify for us as programmers so that we can identify the role of this artifact, this code artifact, usually a class, in our application, in our code base, sorry. So we know this full service, which is basically a class, right, is of stereotype service. So in a multi-tier application, usually having some consistence layer, and we have some domain layer, and then we have maybe an API layer, which exposes the domain somehow to the public. All right, services are somehow located in the domain layer. So by dealing with so-called entities, so here we have our full entity. All right, a regular class, which extends a public object. Before we go into the details of this full class, of this full entity, let's discuss the public object first. What is a public object? Basically, it's just an idea, how to extract some commonalities in our code base and into a base class. Basically, this public object is an abstract class, so generic abstract class. It has this id and life. The idea is that every entity which is exposed or is a candidate to be exposed to the public is a GraphQL thing. It's a public object. As you can imagine, in our relational database, in our relational database schema, let's say it like this, we have some entities that shouldn't be exposed to be public. We need them maybe for technical reasons, so they have some relations maybe between different kinds of entities, but they aren't a candidate to be exposed to the public. But we identified in our application that public objects, so those objects which are a candidate to be exposed to the public, have some commonalities, basically an ID. All the public objects we're dealing with have an ID. We also have this fancy life object, life means we have this created at timestamp, updated at timestamp, and deactivated timestamp. As we'll learn in a second or so, those fields aren't really, there's no need for us to manage them on our own because we are auto-filled filled using this TypeORM capabilities. So this created date column, decorator, and the update date column decorator come from the TypeORM packages or provided by TypeORM. So we don't really have to care about this, the values of this created end timestamp and update at timestamp. Whenever we update or create an entity using the so-called entity manager in the TypeORM world, those fields for this instance are updated automatically for us. Deactivated add field, not really. So that's a strategy which is very common in application development in general. Maybe for... Legal reasons. So as you know, today we can't really, we're not really allowed, even if we want to do so. Delete data, we have to keep them still in our database somehow for some reason. If some criminal activity happens, we have to keep still have to them. So and also deleting instances out of our relational database usually leads to a lot of problems. Because as the name suggests, it's a relational database.

15. Managing Deletion and Object Relations

Short description:

When deleting instances, it's important to consider related entities and use the deactivated at property. Public objects have auto-generated IDs, often using UUIDs. Annotations in TypeORM and GraphQL are similar, allowing for a consistent class structure. Bidirectional relations and lazy loading can optimize performance when accessing related data.

So there are potentially a lot of our entities which are related to the object to be deleted. So the delete operation to implement is not an easy one. So that's a cool trick to keep track always on such objects are deactivated at timestamps potentially, which is an option. So it can be nullable. Usually by default, it's nullable. So it's an active object because deactivated has its null. And we consider this deactivated at property running SQL queries. And we always ask the deactivated null not equal to null. All right, in order to have only the active ones. It's much cheaper when dealing with this complexity of deleting instances usually.

So we said the public object is basically something which has an ID and a life. Also the ID is created by us, but also auto generated. Here we also use a com capability of a utility actually of the type on word to use generator. For auto-generated columns. What's actually possible here in search. Let's take a look. You are the row ID increment identity, potentially all well-known database management systems like my sequel, Oracle and Postgres and so on. They know this increment is auto increment thing, right? But for public objects, we usually want to have something like UUIDs, so not really predictable IDs, right? That's also for security reasons, but also identifies us usually very nicely, like somehow in the UR. And UUID has to be supported by the underlying database data management system, base management system and other hoods and Postgres supports it very well, right? Out of the box. So it can be done here.

So before we jump into this annotations, which are important because we have two words here with this annotations. Some of them are for GraphQL and some of them are for Typeorg. And here's the good news, that usually the idea behind this decorators as in the TypeScript, sorry in the Typeorg words, the ideas behind it are the same as in the GraphQL words. So you can establish some kind of a pattern in your head, right? In order which decorators are actually needed in order to have the same class for your database, for Typeorg, as for GraphQL. So, yeah, I said, okay, my foo is a public object. So it comes already with this id property and it comes already with this live object, but additionally to it, it has this text property and this relation to the bar property. Right? As we can see, bar is a public object as well. So it has also an id of type UUID and this fancy live object, additional column, maybe the text and a relation to the parent. So basically it's a bidirectional relation. So it's very necessary while modeling in GraphQL to say if a relation is unidirectional or bidirectional. Depending on this information, apply this annotation's a bit different. So it's the declarations a little bit different. It turns out also to be a good idea to have in the case of relations, this lazy flag set to true. What does it mean? Usually when you use the so-called entity manager for accessing different foos, let's say different foos. So you get an array of foos as a result. You don't really load for each of the foos the complete bars array because it's a very expensive operation. Maybe you don't really need the bars. So let me give you an example. Here I have this all foos. Let me send it. All foos, why is it empty again? Because I recreated. Sorry. So I can get it again. Let's create a foo. It is. For foos. Here it is. So to access this bars, it's a very expensive operation that this turns out to be. So we accessing each of the foos first and then for each of the foos, we have to query, the data base in the game in order to access the bars. But maybe they don't need the bars. Maybe I'm not asking for them. Right? Why should I query this bars anyway? So it turns out to be a good idea in a GraphQL world. TypeROM is not binded to Type, sorry, to GraphQL. But in a GraphQL world, it makes pretty much sense to say all those relations are lazy. So on demand. So therefore lazy operations are always promises. So therefore this async work only resolved when it's, okay?

16. Entity, TypeORM, GraphQL, and EntityManager

Short description:

The entity is important from the perspective of TypeORM, as it represents a table. It's crucial to ensure that the TypeScript and schema information are in sync. GraphQL uses decorators to define object types and interfaces. Operations on entities are typically implemented in services, with the EntityManager as a first parameter. Using a transactional EntityManager allows for atomic behavior when working with multiple services.

The most important one is entity. It's that from a perspective of type ARM, who should become a table. So basically it's not a completely true entity from a perspective of a system architecture. It's an entity, so somewhere in a domain driven approach, it's some kind of a business object, but it also means from a perspective of type ARM, hey type ARM create table for us, right?

Actually let me say, take a look here. We have exactly this Foo here. All right here it is. And ID created, updated, deactivated. So this add entity states it's an entity created a table for it. All right. This column says, okay, this is the column of the table to be created. It's not nullable. Right. Two words again, you can make a lot of mistakes here. The most prominent mistake is to say, okay, here it's an optional, and here's the false, right? So, actually it doesn't really match, right? So, from the perspective of our compiler, from the perspective of our TypeScript compiler, it's an optional, it can be null or undefined, right? But from the perspective of our schema, it's not nullable. So, this is a common mistake which, at runtime. Always consider the TypeScript is a built-time-only story. All right, so at runtime, everything is JavaScript. So, at runtime, you don't have information with TypeScript information with static type information but it should be, but it's potentially an optional or not. So, always make sure to have this here in sync. All right, so it's not nullable. So, it's also not an optional from a perspective of TypeScript. Make sure it's in sync. So, what's the column? This is the column of the perspective of TypeScript. One too many, also something which comes with TypeWRONG which means, okay, this bar is represented by the bar entity. It's a B directional entity relation. So, it's a B directional relation. So, when we have a particular bar, this foo, we are on side, this instance of foo is somehow related to this dot foo. And we already talked about this lazy flag here. So, cool. But what is this? As it turns out, GraphQL has also some kind of decoration, decorator. usually, object type comes with entities. So usually, when you have here this entity, you have this object type from a perspective of GraphQL. So with object time, you also say, Okay, this here should become part of the GraphQL schema. If you forget this object type, it won't become off the graph scheme to be complete. This implements here is also crucial because here, this entity says, Okay, we have an extensive relation with a public object, but there are no extents or no inheritance, class-based inheritance in a GraphQL, but we have interfaces in GraphQL. So this public object is also an interface from the perspective of GraphQL. Let's take a look on it. It's interface type comes with GraphQL. And we're saying, okay, public object. So usually, extensions here, sorry, there's some inheritance, class-based inheritance comes together with implements property of object type. And here you see the field. So, although here's a, from a type, type on perspective, for decorators, might be a little bit complicated from a perspective of type on, sorry, GraphQL. It's quite simple. It's always named at field. And as you can see, those fields match. It's got variations match. So, we use it as standard here in array. And so on and so on. Quite simple. Right here.

What can we do with this public objects? Or first of all, where are actually all our operations implemented? So, where is the storage or the accessing of this entity? Where does it happen? Usually in the attached services. You have the same idea. So, basically services are technically injectable, so using the dependency injection subsystem, right? And here you have a couple of methods. A good pattern here is to have always an EntityManager as a first parameter. So, here you have an insert operation for creating a new foo, for example. Right, we are passing the EntityManager as a parameter with a given input. The input is part of a schema, of a GraphQL schema, input type, GraphQL input type. That's exactly the object we are passing here. Some implementation, we won't really focus too much on it, but basically we're using the EntityManager for creating new instances based on the input. Also the relations in this case the bar, and save it in the end that we have already in a managed full object as an outcome without generated input ideas or the timestamps, and so on.

I like to give you also a good reason why we'd like to use this EntityManager here as a first parameter instead of let's say, injecting the EntityManager using NestJS own facilities like repositories, for example. The reason for it is that we can find ranked work with so-called transactions. So imagine you have operations using full service, also the bar service, you had multiple insulates and so on, and you have want an atomic behavior. So what you say all or nothing. I want to see all those operations running successfully or everything should be rolled back in such scenario. You don't want to have a regular entity manager here but you use a transactional entity manager. Pass this entity manager here's a parameter. The reason is simple. Entity service of our service here which we have just seen, can use other operations of other services which also takes the same entity manager as a parameter. Having this same entity manager always as a first parameter ensures you that you can pass in a transactional entity manager inside it.

17. Entity Manager and Error Handling

Short description:

Having the entity manager as a first parameter allows for passing a transactional entity manager, ensuring that if any operation fails, everything is rolled back. This simplifies implementations and eliminates the need for specific error handling.

Having this same entity manager always as a first parameter ensures you that you can pass in a transactional entity manager inside it. Whenever one of these operations fails, whenever one of this operations fails for some reason, everything is rolled back. This is a very cool thing because it simplifies also your implementations. You know some people tend to say, okay, the first thing we have to do here in such an operation is to make sure that operations are valid. We have to validate some things or make sure some things, you don't really have to do it yet. I don't talk about validation, backend validation which already have to be done, but some things with error messages, for example, so for error code or 500 error codes, usually you don't really have to deal it here in a very specific manner. Just throw an exception wherever you feel so, it rolls your transaction completely back. Everything which involves persistence on your database system, rolls it back.

18. Service and Query Operations

Short description:

A public object service extends the base implementation and includes common queries like find all and deactivate. It also has operations like ensure exist or throw to check the existence of requested entities.

What's a service with an insert operation? But where are the query operations? So as this turns out to be, it's a public object service, right? So here's a very specific thing, public object service extends. We have already on the base implementation some queries, some very common queries like find all, deactivate, right, for deactivating things, for selecting things, using cilinder as a query builder, and even operations like ensure exist or throw, which are very common, to make sure a requested entity with which we're working on with the given ID even exists. So I don't want to dive too much into this implementation, it's maybe something you can do on your own, because it doesn't make sense in this code.

19. Introduction to Peer Entity and Code Generation

Short description:

We haven't seen the resolver yet, but it acts as the firewall between the back-end application and the client. The foo resolver handles common operations and entity-specific queries. We'll now introduce the micro-event and user entities, establish a relation between them, and expose them to the public. After that, we'll focus on writing queries using the client and move them to the front-end application. We'll create a new entity called peer in our GraphQL API and generate a complete CRUD resource for it. The app module will be updated accordingly, and we'll rename the necessary files and services to reflect the changes.

A brief thing, one thing we haven't seen so far, is the resolver. Last thing, resolver is, let's say, the firewall. It's this part of your back-end application which talks to the client. And here we have this, sorry, the wrong part, the foo resolver. Here's the foo resolver for the application foo. It's named foo resolver. It's also with some magic inside it, with some public object resolver for common operations where you name the operations like when all foos foo to activate foo. And some very entity-specific queries, like create foo. Here we have this create foo input with this transaction manager. And here you just call this entity service you've just seen to pass this input.

Okey-dokey. That's the so-called mixing. I guess now you've seen everything which makes up this small application. It's quite a lot. I guess most of you are already exhausted or try to follow. From now on, after a very short break maybe of five minutes or so, we'd like to continue with our micro-events applications. We'd like to introduce a new entity micro-event. We'd like to also introduce another entity, which is user. Let's name it maybe peer in our world. Bring them both into relation so that we have meeting in our database. Let's expose this micro-event and the user to the public. Then we're done with the NestJS part, with our API part. And then we focus on writing queries. Therefore, for writing queries, we use the client. We don't go into the front-end application directly. But instead we focus on our playground or maybe Altair, if you prefer. You define some queries, maybe some mutations. The next step would be to move these queries and mutations into the front-end application as we've already seen, here inside this GQL queries. We autogenerate type definitions for those queries. And then we focus on the front-end development, which is the component, the pages.

So, let's continue. We'd like to create another entity, another feature in our API application, basically in our GraphQL API. We open the terminal, the right terminal. The right terminal is this one attached to API or inside the API project. Basically, we're running here, so let's create another one in the API project, not a debug one but a temporary, regular terminal. And let's run a nest command, a nest-cli command. So, the nest-cli is this nest here. So, you can use nest g for generate. Then you have a couple of options. You have multiple artifacts, right? For us, most important one is usually by R, and so not for R, REST, REST resource. But we would like to create a complete CRUD resource with all the necessary artifacts. So let's use it. Nest generate REST, and let's name it peer, right? I really avoid the name, user, I throw that the name user because somehow it's a very common term, right, for a lot of things, my application, each micro event as multiple peers attached to it. Basically, it's a user. So a couple of questions here. Rest AP9, no, we're not using one. Would you like to use GraphQL code first? So that's our approach here. Would you like to generate CRUD entry points? Yes. All right, so we've got a lot of code generated for us as you can see, right. And also the app module is updated. Let's see it, updated module. Here we have a dependency to peer modules. So the app module knows from now on the peer module.

Okay, we could do it like this, and now doing all our things manually. Nevertheless, I like to use the lazy man approach here instead of auto generating, which is already the somehow lazy man approach. But instead I say, okay, let's remove the peer again. I just copy paste this Foo here in my code and rename it Foo is a peer. Why? Because my codes from this Foo module is already very generic. I'll use a lot of things inside it, but it's a very generic code. So from now on, I'd like to do some renaming. That's so simple operations here. Starting maybe with a Foo module. From now on, it's not a Foo module, but a peer module. Alright, peer module. Let's rename also the file accordingly. Okay, cool. Foo service. It's not a Foo service. It's a Peer service. And exactly, it's a Peer service.

20. Renaming Peer Entity and Input Type

Short description:

Let's rename the file as well. The Foo resolver becomes Peer resolver. This is Peer resolver. This also provides entities. So I don't have so many entities inside this Peer feature. Instead of it, I only have one. So let's rename all this as well. Decals becomes Peer. It's also public object, let's rename the file. Let's do some renamings here as well. We have a dedicated type of ID, and we don't have this relation. So what is my Peer? Let's focus maybe a little bit on this. We don't have a text. We already have from this public object, this ID, this ID of type UID and this fancy live object. But maybe I have a user name. Right, user name is a string. It's also required from the perspective of type on nullable is false, it's the default. So I don't really have to write it but I'd like to be very explicit here. And it's a column, also nullable false. The first one is required to have as a field to have this as a field in the GraphQL schema. And this one is required from type of perspective, right? So let's clean up a little bit. So basically we're done here with our peer. It sounds a little bit stupid to or lazy to work like this but it's exactly that's where most efficient way to code, right to some initial codes which already works for us, but we checked, okay, everything is fine, everything is working, doing in a very generic approach. So working with mixing, working with generics. For example, it's usually a good idea and being doing some basic renamings. So we have our peer entity. Let's focus on the input type. What is actually from the perspective of, from the perspective of, uh, buh, buh, buh, of GraphQL input in order to create, not the foo, but a bar. Let's name it here as well. Not the part, sorry, peer. Yeah, here, Germany has already quite, quite great peer inputs. Right? So we need at least the username. Which is a string. And we say, okay, it's a field. Right? So in order to become a type, and also if input of this of this input type, input type is something which is also reflected in the GraphQL schema. We need this field here as well. So it's enough for this. Save. Save so long.

Let's rename the file as well. The Foo resolver becomes Peer resolver. This is Peer resolver. This also provides entities. So I don't have so many entities inside this Peer feature. Instead of it, I only have one. So let's rename all this as well. Decals becomes Peer. It's also public object, let's rename the file. Let's do some renamings here as well. We have a dedicated type of ID, and we don't have this relation. So what is my Peer? Let's focus maybe a little bit on this. We don't have a text. We already have from this public object, this ID, this ID of type UID and this fancy live object. But maybe I have a user name. Right, user name is a string. It's also required from the perspective of type on nullable is false, it's the default. So I don't really have to write it but I'd like to be very explicit here. And it's a column, also nullable false. The first one is required to have as a field to have this as a field in the GraphQL schema. And this one is required from type of perspective, right? So let's clean up a little bit. So basically we're done here with our peer. It sounds a little bit stupid to or lazy to work like this but it's exactly that's where most efficient way to code, right to some initial codes which already works for us, but we checked, okay, everything is fine, everything is working, doing in a very generic approach. So working with mixing, working with generics. For example, it's usually a good idea and being doing some basic renamings. So we have our peer entity. Let's focus on the input type. What is actually from the perspective of, from the perspective of, uh, buh, buh, buh, of GraphQL input in order to create, not the foo, but a bar. Let's name it here as well. Not the part, sorry, peer. Yeah, here, Germany has already quite, quite great peer inputs. Right? So we need at least the username. Which is a string. And we say, okay, it's a field. Right? So in order to become a type, and also if input of this of this input type, input type is something which is also reflected in the GraphQL schema. We need this field here as well. So it's enough for this. Save. Save so long.

21. Creating Peer and Resolver

Short description:

In the peer service, we focus on the insert operation to create a peer using the entity manager. The create operation sets the fields for the new instance, such as the username. After creating the peer, we save it using the entity manager. Moving to the peer resolver, we use a public object resolver to provide queries and mutations. We ensure that the names of the operations are globally unique. We also add a create operation to handle the creation of a peer. Finally, we check for any compilation errors and restart the application if necessary.

Okay. So we have this CreatePeerInput. We have this peer entity. Let's focus again on the peer service here, because things become a little bit more complicated. We have this peer service working on the P, on the P-ID. We'd like to identify it in log messages as peer. And we'd like to focus on the insert operation. We already have a lot of operation here in the Base class, right? Find all, query find all, select and show existed throw. Deactivate, find one. This, I guess is also inserted somehow select. Where is it? I can't find it. Find one, here it is, a simple operation. So a lot of operation we get by free using this public object service Base class. Here we have only to focus on the creation operation. So let's quote it by scratch. create foo input becomes create peer input. And it should return a peer. We're using the entity manager, where we say create, those parameter is the class we'd like to create, peer. Then we pass some fields. So the peer has a username, this ID and life are managed basically by our Base class. So ID is auto-generated, life is also managed by the Base class, but the username is something which we have to actually add here from this input, username, do this. The result of this operation is a peer, right? A peer instance created using the EntityManager. Now we have to save it. So return EntityManager, save. I guess we're done with it. It's a very simple operation using the EntityManager, we use the create operation, stating which class we're operating, or the peers is always the first parameter. And here are the fields to be set for the new instance to be created. Here it is, but it's still not saved. So we have to use the em.savePeer. And from now on here where the result is, so here where my class actually is, this auto-generated fields are also populated. So we're done now with the peer service as well. Let's go to the peer resolver. So we'd like to have a resolver for the peer. Here we provide all the operations, which creates queries and mutations. So we use a public object resolver with some magic, with some magic attached to it. Basically it's a mixin. So we're saying for the find all operation, we'd like to name the find all operation peers. Find one, we'd like to name peer. And deactivate operation, we'd like to name peer. Deactivate peer. Oh, yes. Keep in mind that all of these queries and mutations have to be unique, globally unique inside your schemata. So you can't just pass your generic names. Like, let's say, find all or find one or deactivate and so on. So always when naming your operations, you have mutations and queries inside Resolver, make sure they are globally unique. Find a good patterns that works for you. Also, some... Useful naming spear service. So, we have also a lot of magic using this public object to Resolver, like, which provides us some queries and mutations for free, as already said, now for the find all, find one, or deactivate, right? Which already works quite well for us, but at least one specific we need, which is create operation, not create for but create here, which is, let's name input somehow, also makes sense to rename it here. Entity service insert upset P input upset rent offset, avoid naming create P inputs, makes more sense. And then so P resolver is I guess done. Let's fix. What makes up my P module in our case, we need at least this P here, we don't have the bar. Here we go. P is hopefully done. Let's check it, if it work. When we look, ooh, something went wrong. So not everything is working. I think I could try before, actually reading this error message is to restart the application. Okay, something went wrong. Nothing what I expected. Unable to, bar is not defined, so I have this bar somewhere already. I still missing, probably some, it's a compilation error I guess, entities for entity. I think I make, I made some, somewhere mistake, but where? Okay. So that's actually common, but the error messages you get are not really specific, not very precisely, and somehow, sometimes even not right, so not stating our years through entity. This one thing you can always do if you can't figure out what's the reason for it is to remove a sort of cold dist folder, right? So NestJS manages this dist folder where it creates its cache, right? So maybe some immediate results are cached incorrectly on set it. I, as already said, I moved the module, I recreated, renamed a lot of things, maybe things went wrong here. Oh yeah, it was the case. So everything worked after removing this dist, which also consists of a cache. So next thing we can do right now is to check Postico or whatever you'd like to use.

22. Checking Generated Schema and Writing Queries

Short description:

Here's my peer, exactly what I expected. Let's check if it's part of the generated schema type. It is. The Pier has ID, life, and username. The mutation for creating a pier requires a username. Let's focus on queries and mutations. I'd like to write a query for all peers and all active peers. I'd like to have the parameter take or skip.

Let's load it. Here it is. Here's my peer exactly what I expected and ID, username created, that updated that, deactivated that, of type UUID, everything seems to be fine here. So next thing to do, again, back to a API. And let's do the same, almost the same. Note, because we're running a little bit out of time. Don't do it one more time, which is basically the same operations. Copy and pasting, define some additional columns and renaming things. I leave it with peers, right? So we don't run out of time. So we have this peer. Let's check next. If it's part of a generated schema type. So let's reload the schema, and let's make sure it's done. Here we go to the docs. Oh, sorry. We already are in the docs. Let's go home. And let's see, back queries. Who's? Oh no, not what I expected. Something went... Haven't worked for me. Oh, I have to think. I have to think. Seeing the same. Sorry? I'm also seeing that it's not in docs, but I have everything else working. Okay. So what is it actually part of a generated schema term? Let's check playground maybe. Playground here this. Here we have all the queries, the activated foos, schema. We have this live object, this public object here on the right side. So what's the generated schema life. The term, public object. Public object. Foo, we have a foo, we have a bar. Queries, also I forgot something. I forgot something. Example part of. Oh I know what I forgot. I forgot to put this just, just generated modules here as a reference lab manual. Here it is. Wait. Error link. And check it, maybe again. Oh, it's here, oh. So Piers, Pierre. Right and we have also two mutations create pier and deactivate pier for us. So let's check the Pier for example. The Pier has ID, life and username. It also has something I'm missing, oh no, I like to check the query. Not the query, the mutation sorry. The mutation for creating a pier, to create Pier input requires a username. So everything is working. Let's focus on queries and the mutation of a one query and one mutation maybe we'd like to, we'd like to write here. So again, docs. I can start with maybe with collection of selected piers. I'd like to name it, query all peers. This, and I'd like to say, okay. Same with all active piers. All active piers, so like this. I'd like to have the parameter, take or skip. Which is. What's the question? I'm seeing that you have query, all active peers here, but I only have the query objects without the query keyword. Is this optional on line six? So, what do you have this year? I have run query and then I have the object. When I click, create query from the docs, it creates an object with peers, common, everything you have from line seven. I think that's exactly what it creates. So, again, query, peers, add to query. So, actually it's an unnamed query, anonymous query here. Actually, that's important to state. So, basically this is here, this almost the same syntax as resolving fields. So, for example, this field here, let's say username, right, this username could be also a field to be resolved.

23. Dedicated Resolvers and Performance

Short description:

You can write a dedicated resolver for each field, but keep in mind that it has some cost. It's not necessary, so avoid doing it.

So, we could also write a dedicated resolver for this particular field. So, for example, username could be something like this, where we also pass some parameters inside it, right? Right, so GraphQL is very fine-grained, even on the atomics. So, even on this primitive data types, even on the leaves of this tree, of this object tree, right? So, you can, even for each leaf of this tree, write a dedicated resolver. So, for example, to make some modification for a username, to have it in uppercase, or something like this, right? It could be possible, it's also very well-supported in NestJS or GraphQL bindings, Apollo Server bindings to NestJS, in this case, you write dedicated resolver for fields, but you keep in mind that resolving, having in such a fine-grained, it's always has some cost. And so, always GraphQL... With GraphQL you should keep in mind that writing resolvers for dedicated fields has some cost involved. So it's not really necessary, don't do it, please.

24. Adding Parameters and Testing Queries

Short description:

We introduce parameters for the all peers and all active peers queries, including skip and take. We test the collective peers query, which returns no peers. We then create a peer using the create peer mutation with a username parameter. The mutation is successful, and we test the all active peers query again. The API appears to be functioning correctly. In the front-end application, we create a file named all active peers.ts and define the all active peers query using GQL. We also create a create peer.ts file for the create peer mutation. We run the code generation script and start working on the index.ts file in the GraphQL folder.

So, very, all, all peers, all active peers, with some parameters inside it. What is this common thing here? Collection common input is Active, range order by direction, order by noise, that's already things which comes with this basic implementation of this public object, and the public object resolver. It's already attached to it. So we can choose to have Active always set to true. Oh, sorry, to Active, it's a union, sorry, enumeration, Active. Range, it's a collection range input, what's a collection range input? Skip and take. All right, so let's say skip is something we'd like to introduce and take is something we'd like to introduce as a variable as well. So let's move no, let's move both of these parts here, both these parts here, skip. Which is a, per, per, per, an integer, I guess. Not sure, but I think it is. Take it this and integer. It's also optional, you know by default in a GraphQL all types are optionals. If you don't want to have the optional, put this, I forgot the symbol right here, this mark behind it. So no variables, we don't pass any, we leave it by default which is null. Let's execute it, collective peers gave us no peers so far so good. So next thing to do is to create a peer which is a mutation. Let's go back to mutation, let's choose create peer. I'd also like to pass the name here, create peer. Okay, we have one parameter which is user name and of type string and it's required, always required so make sure, I'll pass it here. And let's pass it as well. One dollar sign is too much. I think it's okay, let's try it. It's a very nice username, maybe my name, and execute. So created successfully. Let's go back to all active users. Let's run this query here, so it works as well. So we're done, our API or what we actually tested seems to work for us. So let's go back to our front-end application to our GraphQL folder. Here it's also quite simple. Create a file, which is somehow similar or somehow named similar to the query itself, so all active peers make sense, pretty much sense for me. I'd also like to start with an uppercase letter. Here in this case, why? Because all these namings are reflected somehow in the generated code. So that's also to see if this relations, it makes pretty much sense to me. Import from, not sure about it, Apollo client. There it is. And here we have something like GQL. Here it is. So we need one constant and also all active peers. And here I go to uppercase, all active peers. And here I'd like to use the GQL tech, former script feature with the template string, Bactex here and copy, paste. Oh, sorry, copy, paste what I just tested. Oh, too many windows sometimes removed. So it works for me. So all active peers, another one, we have one mutation. This one mutation is create peer. So let's name it like this. Take two. R. Create peer ts. Export. Gqr from Apollo client, makes sense. Export. Create peer. Gqr. Oops, that's not what I'd like to paste. I like to paste the mutation. Let's test it. Do this. Oh, something... Oh, const. I forgot to keep const here, of course. It's a constant. So, I've got this query and the mutation. Next thing to do is to run autogeneration. So, yarn gql code gen generates the auto. The query for me seems to be working. Let's start with a simple page. Dedicated folder keys. We say we need an index file. index ts.

25. Moving Code to Custom Hook

Short description:

We are running a little bit out of time. Let's check if everything works as expected. So where is my page? Here we go. Don't have any foos. Check peers. We have one active peer. Here it is. Maybe username. So username, here I am. This code here, it's a very good candidate to be moved to a so-called custom hook. Let's start maybe a new folder, domain. Inside domain I place peers, so from a future peers, instead of a future peers, I would like to paste an index file and inside the peers I like to place the use active peers TS file. For the custom hook, which is export const use active peers, which returns something, we have to stay focus a little bit on what it actually returns. For now, let's leave it empty. Let's copy, paste it and move it here. Let's auto import certain things. We have all active peers here. So, let's define result time interface. Use active peers result, where we have these all active peers. But we don't really care about the small active peers. We care about the peers inside this all active peers thing. Peers, not really nice. Too nice, so let's define posts. Type type, here. Let's say, here we have our pears. Also like to have a loading flag. Of type Boolean. And an error flag, of type Apollo error. Is actually my desired type. Make sure to return exactly this. So we are returning Pierce.

We are running a little bit out of time. So, again, sorry for this. I make this lazy man approach. And say index ts is a copy. That's not what I wanted to copy. I wanted to copy this one. So, we have our p-code page. And also some renamings. Always use this refactoring features of Visual Studio Code or of UID instead of just renaming. You know, I'd have to make sure that you use the right data, or p-page seems to be fine. I used one, I don't need it. Or active. Here it is. Loading, or active posts. Let's rename it as well. This is here. Yeah, so the auto, correct, auto, intellisense is not working because we forgot something very important. We are not, we should always rely on this data types from tables, the text title has to check first of all, password correct, query and set it, which is all active peers, and the typings. All active peers, and all active peers variables. Alright, do this. Where we are? So now it should work. Yes. Yeah, it works. And here. And here, ID. So I think, we are fine Let's start replication. Which is, yarn def. And let's check if everything works as expected. So where is my page? Here we go. Don't have any foos. Check peers. We have one active peer. Here it is. Maybe username. So username, here I am. So time for one last thing. This code here, no. This code here, it's a very good candidate to be moved to a so-called custom hook. So next. So let's try this next. Let's start maybe a new folder, domain. Inside domain I place peers, so from a future peers, instead of a future peers, I would like to paste an index file and inside the peers I like to place the use active peers TS file. So for the custom hook, which is export const use active peers, which returns something, we have to stay focus a little bit on what it actually returns. For now, let's leave it empty. The first step approach is just to move on. Oh, what is this index? Oh no, it's offline. First of all, where is our page? Inside in here, we have this already existing code. Let's copy, paste it and move it here. Let's auto import certain things. We have all active peers here. So, let's define result time interface. Use active peers result, where we have these all active peers. But we don't really care about the small active peers. We care about the peers inside this all active peers thing. Because, so, use of type all active peers. Peers, hmm, not really nice. Too nice, so let's define posts. Type type, here. Like this. Let's say, here we have our pears. Also like to have a loading flag. Of type Boolean. And an error flag, of type Apollo error. Here we go. Is actually my desired type. Alright. Make sure to return exactly this. So we are returning Pierce. So it's like that's correct. Eta Pierce.

26. Simplifying Code and Working with Apollo Client

Short description:

In this workshop, we've seen how to simplify our code by identifying and utilizing generic patterns. We learned about the base object concept, which allows us to express commonalities in TypeScript. We also explored how to extend the GraphQL API using decorators and annotations. It's important to pass the entity manager as a parameter to enable flexibility and simplify implementation. We discussed the different instances of Apollo client and the rendering possibilities, including server-side rendering and static site rendering. When using methods like getServerSideProps, a new Apollo client needs to be created on the server. Overall, it's crucial to understand the nuances of working with Apollo client in different contexts.

Eta Pierce. Not sure if you can do it like this. Okay, so it's a unit data, it doesn't make sense. So let's do it completely. Eta Pierce. Of course this P is might be not loaded. If it's still loading. Now we need this loading operation. If it's loading and we need the error as well. So some mistakes, the new ending. Oh, of course. Here's a p not a ps. Here we have this things. Okay. That makes sense. So the first error is an Apollo error, but here it's an optional, obviously not always have some error. So we have our custom hook. It states exactly what it does. Let's use it to simplify what or to clean up our code a little bit. The same with the. Use active peers. Or case when the loading appears. You can simplify it as well. And clean up our imports. So! Use active peers. We find here as well. I don't like the import. So we use the index.file, export. import.. From useActivePeers. Click again here. Importing directly from peers. So basically that's it. from our workshop. Do you have any questions? So something in mind, would like to say. So I guess it was, well it's very intensive, what we seen, so far. What I like to do after this workshop is to commit, this changes, or what we develop here together. What you can see is,ux when you find some generic patterns for yourself. How to simplify your work. As I did. For example, in the API with this full, with this commonalities, right. So where I said, okay, very something like a base object, like a public object. Something which is exposed has some commonalities. Right. Right. Basically ID and the life object. It can be expressed in TypeScript in a very generic way. Also the service and its operations can be expressed in a very generic way. And the resolver. Which is basically working on both. We require some advanced TypeScript knowledge and how to work, for example, with mix-ins. That's just one approach of things can be done. It can be done in a much simpler way, using inheritance, for example, instead of mix-ins. Choose an abstraction whatever you would like. Also, we've learned that GraphQL, by actually, this annotations, this decorators, which come with Apollo GraphQL or actually the Sjs bindings to it and type-OM. Somehow similar decorators, that we've seen on these entities, for example. Having this bridge got written, this API can be extended very easily, so that we can focus more on the business parts of our API. You have the flexibility to add your own query methods and your own annotations if this what public objects might have been offered to you at get what public objects share, those commonalities are not sufficient for this very particular entity type. That's why it's still very easy to extend it. If you get any scene. One recommendation I'd like to give you is to all not to rely on the facilities of nest.js or over team states, something different, but to pass the entity manager. So this comes to this thing, which comes with type on itself as the first parameter to each method, which gives you the flexibility to nest different service method, cause for some within a service, a users methods of service baby, always by passing the entity manager. Right. And deciding on the most top on the topmost level. It's a regular entity manager or transaction entity manager, for instance, the laws of us to simplify our implementation or ideally into a type form. You can throw exceptions everywhere you'd like, which role was your transaction? It grows back to transaction and all this operations you already done based on entities of obviously, from a perspective of front end application. The most important or crucial thing to do is to understand that we have. We're dealing with different instances of Apollo client. We have different possibilities to do rendering. I have on the front end, the web client itself, so a web browser or using server-side rendering on demand or static site rendering, what we haven't seen so far in this workshop. And using this typical use query and use mutation hooks is only possible if you choose to do it in the web browser. If you rely on methods like shown here, for example, get server-side props, for example, you have to create on the server a new Apollo client. Both queries you execute on the server are not trackable here inside in the front end. So you have to find another way to do so.

Watch more workshops on topic

React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
GraphQL Galaxy 2021GraphQL Galaxy 2021
140 min
Build with SvelteKit and GraphQL
Top Content
Featured WorkshopFree
Have you ever thought about building something that doesn't require a lot of boilerplate with a tiny bundle size? In this workshop, Scott Spence will go from hello world to covering routing and using endpoints in SvelteKit. You'll set up a backend GraphQL API then use GraphQL queries with SvelteKit to display the GraphQL API data. You'll build a fast secure project that uses SvelteKit's features, then deploy it as a fully static site. This course is for the Svelte curious who haven't had extensive experience with SvelteKit and want a deeper understanding of how to use it in practical applications.

Table of contents:
- Kick-off and Svelte introduction
- Initialise frontend project
- Tour of the SvelteKit skeleton project
- Configure backend project
- Query Data with GraphQL
- Fetching data to the frontend with GraphQL
- Styling
- Svelte directives
- Routing in SvelteKit
- Endpoints in SvelteKit
- Deploying to Netlify
- Navigation
- Mutations in GraphCMS
- Sending GraphQL Mutations via SvelteKit
- Q&A
React Summit 2022React Summit 2022
136 min
Remix Fundamentals
Featured WorkshopFree
Building modern web applications is riddled with complexity And that's only if you bother to deal with the problems
Tired of wiring up onSubmit to backend APIs and making sure your client-side cache stays up-to-date? Wouldn't it be cool to be able to use the global nature of CSS to your benefit, rather than find tools or conventions to avoid or work around it? And how would you like nested layouts with intelligent and performance optimized data management that just works™?
Remix solves some of these problems, and completely eliminates the rest. You don't even have to think about server cache management or global CSS namespace clashes. It's not that Remix has APIs to avoid these problems, they simply don't exist when you're using Remix. Oh, and you don't need that huge complex graphql client when you're using Remix. They've got you covered. Ready to build faster apps faster?
At the end of this workshop, you'll know how to:- Create Remix Routes- Style Remix applications- Load data in Remix loaders- Mutate data with forms and actions
Vue.js London Live 2021Vue.js London Live 2021
169 min
Vue3: Modern Frontend App Development
Top Content
Featured WorkshopFree
The Vue3 has been released in mid-2020. Besides many improvements and optimizations, the main feature of Vue3 brings is the Composition API – a new way to write and reuse reactive code. Let's learn more about how to use Composition API efficiently.

Besides core Vue3 features we'll explain examples of how to use popular libraries with Vue3.

Table of contents:
- Introduction to Vue3
- Composition API
- Core libraries
- Vue3 ecosystem

Prerequisites:
IDE of choice (Inellij or VSC) installed
Nodejs + NPM
JSNation 2023JSNation 2023
174 min
Developing Dynamic Blogs with SvelteKit & Storyblok: A Hands-on Workshop
Featured WorkshopFree
This SvelteKit workshop explores the integration of 3rd party services, such as Storyblok, in a SvelteKit project. Participants will learn how to create a SvelteKit project, leverage Svelte components, and connect to external APIs. The workshop covers important concepts including SSR, CSR, static site generation, and deploying the application using adapters. By the end of the workshop, attendees will have a solid understanding of building SvelteKit applications with API integrations and be prepared for deployment.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Top Content
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.
GraphQL Galaxy 2021GraphQL Galaxy 2021
32 min
From GraphQL Zero to GraphQL Hero with RedwoodJS
Top Content
We all love GraphQL, but it can be daunting to get a server up and running and keep your code organized, maintainable, and testable over the long term. No more! Come watch as I go from an empty directory to a fully fledged GraphQL API in minutes flat. Plus, see how easy it is to use and create directives to clean up your code even more. You're gonna love GraphQL even more once you make things Redwood Easy!
Vue.js London Live 2021Vue.js London Live 2021
24 min
Local State and Server Cache: Finding a Balance
Top Content
How many times did you implement the same flow in your application: check, if data is already fetched from the server, if yes - render the data, if not - fetch this data and then render it? I think I've done it more than ten times myself and I've seen the question about this flow more than fifty times. Unfortunately, our go-to state management library, Vuex, doesn't provide any solution for this.For GraphQL-based application, there was an alternative to use Apollo client that provided tools for working with the cache. But what if you use REST? Luckily, now we have a Vue alternative to a react-query library that provides a nice solution for working with server cache. In this talk, I will explain the distinction between local application state and local server cache and do some live coding to show how to work with the latter.
React Summit 2023React Summit 2023
24 min
Debugging JS
As developers, we spend much of our time debugging apps - often code we didn't even write. Sadly, few developers have ever been taught how to approach debugging - it's something most of us learn through painful experience.  The good news is you _can_ learn how to debug effectively, and there's several key techniques and tools you can use for debugging JS and React apps.
React Day Berlin 2022React Day Berlin 2022
22 min
Jotai Atoms Are Just Functions
Jotai is a state management library. We have been developing it primarily for React, but it's conceptually not tied to React. It this talk, we will see how Jotai atoms work and learn about the mental model we should have. Atoms are framework-agnostic abstraction to represent states, and they are basically just functions. Understanding the atom abstraction will help designing and implementing states in your applications with Jotai