How to Delete MongoDB Listing With GraphQL API
In this lesson, we'll use our custom server fetch() function to invoke the deleteListing mutation we have in our GraphQL API, to delete a listing in our listings collection.
Deleting a listing#
π This lesson's quiz can be found - here.
ποΈ Solutions for this lesson's quiz can be found - here.
With our custom server.fetch()
function, we've been able to query the listings
field in our GraphQL API. Now, we'll look to see how we can make the GraphQL mutation available in our API - deleteListing
.
In our server.fetch()
function, we've specified that the request body has to have at the very least the query string that represents the GraphQL query (i.e. request) we want to make.
interface Body {
query: string;
}
export const server = {
fetch: async <TData = any>(body: Body) => {
// ...
}
};
We can reuse this server.fetch()
function to help conduct our mutation. The mutation we'll want to make (deleteListing
) expects a variable argument to be passed which is the id
of the listing that is to be deleted. As a result, we should expect the body of the request to contain the variables that can be passed into our GraphQL request.
The JSON body we pass into our request expects a query
field of type string
. The other field we'll pass in is the variables
field which is to be an object for holding the variables that are to be passed into the GraphQL request.
Just like how the data of a request is to be typed, it can be helpful if we're able to type define the expected variables of a request since every request may expect different variables. Because of this, we'll make the Body
interface a generic that accepts a TVariables
type with which will be the type of the variables
field.
interface Body<TVariables> {
query: string;
variables: TVariables;
}
Variables of a request can be optional since we don't have to pass in variables for every GraphQL request. We'll denote the variables
field as being optional by placing a question mark at the end of the variables
field in the Body
interface.
interface Body<TVariables> {
query: string;
variables?: TVariables;
}
In the server.fetch()
function, we'll need to pass the value of the TVariables
type to the Body
interface type assigned to the body
argument. Just like how we've introduced a TData
type variable into our server.fetch()
function, we can introduce a TVariables
type variable as well and give it a default value of any
. We'll then pass the TVariables
type value along to the Body
interface used as the type of the body
argument.
interface Body<TVariables> {
query: string;
variables?: TVariables;
}
export const server = {
fetch: async <TData = any, TVariables = any>(body: Body<TVariables>) => {
const res = await fetch("/api", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
return res.json() as Promise<{ data: TData }>;
}
};
Our server.fetch()
function is now prepared to allow components to make GraphQL mutations. In the <Listings>
component, we'll create a button that'll trigger a method when clicked. We'll call this method deleteListing()
and the button text will be 'Delete a listing!'
. Since our deleteListing()
function will make an asynchronous request, we'll label the function as an async
function.
import React from "react";
import { server } from "../../lib/api";
import { ListingsData } from "./types";
const LISTINGS = `
query Listings {
listings {
id
title
image
address
price
numOfGuests
numOfBeds
numOfBaths
rating
}
}
`;
interface Props {
title: string;
}
export const Listings = ({ title }: Props) => {
const fetchListings = async () => {
const { data } = await server.fetch<ListingsData>({
query: LISTINGS
});
console.log(data); // check the console to see the listings data from our GraphQL Request!
};
const deleteListing = async () => {};
return (
<div>
<h2>{title}</h2>
<button onClick={fetchListings}>Query Listings!</button>
<button onClick={deleteListing}>Delete a listing!</button>
</div>
);
};
The deleteListing()
function is where we'll want to call the server.fetch()
function, pass in the expected GraphQL request and the variables of the request. Let's first define the shape of both the data we expect to retrieve as well as the shape of variables we want to pass in.
In the Listings/types.ts
file, we'll declare the expected types of the data and variables field of our deleteListing
mutation as DeleteListingData
and DeleteListingVariables
respectively.
The data we expect returned from the deleteListing
mutation is the deleted listing itself. So we'll specify a deleteListing
field within the DeleteListingData
interface that will have a type of the Listing
interface we've defined earlier.
This page is a preview of TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL