Making GraphQL Requests With POST and fetch

Numerous tools and libraries exist to help clients make GraphQL requests to a GraphQL API. Before we begin to introduce a third-party library to help make our GraphQL requests, we'll look to make our requests with the help of the window Fetch API. In this lesson, we'll begin to make the connection between our React client and Node server and see if we can query the listings query from our GraphQL API.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.

Thumbnail for the \newline course TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL
  • [00:00 - 00:20] In this lesson, we'll look to make our first interaction with the local GraphQL API we've set up on the server. Now there's a large number of tools in the ecosystem that is the gear to help clients to make GraphQL requests, and these tools provide a lot of value, with which we 'll see eventually, but we don't actually need them to make GraphQL requests.

    [00:21 - 00:38] In the next couple of lessons, we'll be taking our time and looking to make our GraphQL requests through some really simple means, which will give us a good understanding of what it takes to make a GraphQL request. Let's jot down the game plan of what we intend to do to make our GraphQL requests.

    [00:39 - 00:48] First of all, we need to invoke either a POST or GET HTTP method. GraphQL supports both GET and POST, but some requirements at each.

    [00:49 - 01:00] Now remember, traditional REST applications, POST or GET are denoted to invoke what kind of request is going to be made. In GraphQL, however, we address things in terms of queries or mutations.

    [01:01 - 01:18] One main difference between a query or a mutation is that mutations are executed one after the other, while queries are executed in parallel. Regardless, queries are often used to retrieve data, while mutations are often used to manipulate or mutate data.

    [01:19 - 01:36] Since our GraphQL server-client relationship is served over HTTP, we can make either a GET or a POST to invoke a GraphQL request. Most GraphQL clients, however, use the POST HTTP method to both retrieve and persist data, with which we'll be doing.

    [01:37 - 01:51] The second thing we'll do is specify the content type of our request as application JSON. Since we'll specify the GraphQL documents we intend to send, for example, the query or mutation itself as a JSON object.

    [01:52 - 02:09] And since GraphQL APIs have a single endpoint, we'll need to reference the URL of this endpoint when we make our request. Regardless of what library, language, or tool you may be using, we'll essentially need to do what we've just listed to make a GraphQL request.

    [02:10 - 02:29] In our case, since we're building a client app in React, we can use the native browser fetch method to make our request, with which modern browsers in like Chrome supports. The first thing we'll attempt to do is create our server fetch function in a new folder within source we'll label as lib.

    [02:30 - 02:45] The sections folder in source will be responsible in containing the main section components of our app. The lib folder will be where we introduce any or all code that is most likely to be shared between the different components in our app.

    [02:46 - 03:02] We'll create an API folder within lib responsible in setting up the server function responsible in interacting with our API. Inside the API folder will be a server.ts file, as well as an index file.

    [03:03 - 03:27] In the server file, we'll export a server constant object that will remain empty for now, and in the API index file, we'll re-export the server object. In the server object, we'll define a property on the object as given a label of fetch.

    [03:28 - 03:38] This property is to be a function. In the fetch function, we can attempt to use the window fetch method to help eventually make our request.

    [03:39 - 03:50] We'll assign the results of the window fetch method to a variable we'll call response, or res for short. Window fetch is a promise.

    [03:51 - 04:02] We want the results of the promise to be assigned to the response variable. We could use the promise.denseintax, however in our case we'll use the ES6 JavaScript async await syntax.

    [04:03 - 04:21] We'll make our fetch property in the server object an async function, and set the await expression on the window fetch function. The window fetch function is complaining since it expects at least one or two arguments.

    [04:22 - 04:31] When our server fetch function gets called, we'll expect an object to contain the document we have in mind. We'll label this document as query.

    [04:32 - 04:46] In addition, we can expect this object to contain the variables that can be passed into our GraphQL request. We'll create an interface for this object, label it body, ford what our server function will expect.

    [04:47 - 05:02] We'll specify that this object type must contain a query field that is of type string. With our server function now expecting the request body object, we can begin to build out the window fetch method.

    [05:03 - 05:20] The first argument of the window fetch method is a required argument that is to reference the path to the resource you want to fetch. In our instance the path or endpoint of our API is a localhost 9000/api when our server is running.

    [05:21 - 05:35] If we directly placed this URL here, our client web server localhost 3000 would attempt to load a resource from another server localhost 9000. This will essentially be performing cross origin resource sharing.

    [05:36 - 05:50] For security reasons, browsers may reject the ability for our client to make the request to the server. To avoid this, we can have our webpack server peroxy requests intended for our API server.

    [05:51 - 06:13] Update React app makes the ability to proxy requests in development fairly easy by simply allowing us to define a proxy field in our package JSON file. We'll specify a proxy and place a value of the base path of our server endpoint , HTTP localhost 9000.

    [06:14 - 06:40] This rule dictates if a request within our React webpack server is made to an unrecognized request prefix, for example just /api, it will be redirected to the specified proxy, localhost 9000/api. In our server fetch function, we can specify an argument of /api in our window fetch method which will get proxy to localhost 9000/api.

    [06:41 - 06:55] Let's quickly verify what we did for the proxy. We can't really do HTTPS, it should be HTTP since our local development environments aren't secured.

    [06:56 - 07:07] What we have here is appropriate if we're simply looking to get data from a resource. In our instance, we want to post data to our endpoint while passing in the necessary parameters.

    [07:08 - 07:20] We'll specify request options as the second argument of our window fetch method . The first option we'll specify is the method option with which we'll have a value of posts.

    [07:21 - 07:32] The second request option will be where we declare the content type of our request as application JSON. This is to be done in the headers option like so.

    [07:33 - 07:51] Finally, we'll pass in the data that is to be sent as the body of the request. We can't pass in a JavaScript object, so this is where we'll use the JSON stringify method to convert the data body that is being passed into a JSON string.

    [07:52 - 08:04] When the fetch is successful, it returns a JSON response. To have this response handle as a native JavaScript object, we can simply return response.json.

    [08:05 - 08:15] At this moment, our fetch method is a promise that when resolved returns a data type of any. This isn't really strongly typed, but we'll revise that in an upcoming lesson.

    [08:16 - 08:27] For now, we'll verify if we're able to interact with the server from the client with this method. We'll look to query the listings information from the listings component directly.

    [08:28 - 08:44] In the listings.tsx component, we'll import the newly created server object from the lib API folder. To get things started, we'll state that we want the query to be made only when a button has been clicked.

    [08:45 - 08:58] So let's introduce this button element in our component template. We'll attach a click event listener on the button that when clicked, we'll call an accompanying function labeled fetch listings.

    [08:59 - 09:12] We'll place a console log in the fetch listings function to verify if our click event handler works as intended. Opening our browser console and clicking the button will show that we're running the function appropriately.

    [09:13 - 09:23] Let's now attempt to make the server fetch request. We'll assign the result of the server function to a listings variable we'll create.

    [09:24 - 09:38] Our server fetch function expects a body argument with which contains a query field of the query we intend to make. This query will be a string that represents the shape of data we'll like to return from our API.

    [09:39 - 09:50] We'll query the only root level query available in our server API, the listings query. We'll define this query at the top of the listings.tsx file.

    [09:51 - 10:09] To distinguish our GraphQL query document variable from any other variable, we 'll declare the query in a variable named listings in capital letters. Since our request is of content type application JSON and passes a stringify JSON, we'll create our query as a string.

    [10:10 - 10:47] We'll set up our GraphQL query and look to query all the fields from the listing GraphQL object type for the listings query from the ID title to the rank. We'll pass in the body object the server fetch function expects and specify a query field with which the value is the listings query variable we've set up.

    [10:48 - 11:04] We'll make our fetch listings function asynchronous since we'll have to wait for the results from the async server fetch function. We can then place a console log to survey the listings object being returned.

    [11:05 - 11:13] Let's quickly summarize how we're making our query again. The server is the actual listings valuable in our TypeScript code.

    [11:14 - 11:25] This refers to the actual string that represents the query. Below is the query keyword that refers to actually making a GraphQL query.

    [11:26 - 11:33] Queries don't have to have a name, but in this case, we're also able to specify the name of the query we want to make. We could say anything here.

    [11:34 - 11:45] We could say fetch listings, listings, etc. For consistency sake, we usually specify the name of the query to be equal to that of the actual field being queried.

    [11:46 - 11:57] And that brings us down to the field itself. Here is the actual GraphQL field being queried and everything below are the sub fields of that main field.

    [11:58 - 12:16] Let's verify that we're able to now actually fetch with the server fetch function. Our server needs to be running to actually retrieve data, so we'll head to the terminal, start our server application.

    [12:17 - 12:22] And then when we return to the browser, we'll click the query listings button. Hmm.

    [12:23 - 12:35] It seems to say it can't fetch from localhost 3000/api. So this probably tells us that the proxy we set up in Packet JSON isn't working for some reason.

    [12:36 - 12:52] Most likely is due to the fact that making changes to the Packet JSON file isn 't reflected until we exit the Webpack server. So we'll go back to the terminal, exit the Webpack server, restart it again.

    [12:53 - 13:02] And then when it's running, we'll go back to the browser, refresh and try to actually make the request. And now we can see that it works successfully.

    [13:03 - 13:19] So it's actually proxying the request to localhost 9000 and we actually see information in our console. Here we can see the three listing objects that are actually stored in the listings collection of our Mongo database.

    [13:20 - 13:45] We are querying all three documents, which are essentially all the documents we have in our database and our polar server API actually returns the data under a field denoted by data. So what we can do now is in our code, simply destruct this data to simply retrieve the listings array directly.

    [13:46 - 13:58] And there we have it. With a very simple fetch method, we've been able to fetch and make a GraphQL query to our GraphQL API to retrieve the data we want.

    [13:59 - 14:12] Though our simple custom fetch function works, there's a few areas of improvement we'll need to make. And we're going to start by looking into how we can type define the data that is to be returned whenever we use the server fetch function.