So far, we have been simply requesting data from a server, but that is only half the battle. We also need to be able to send data to a server — sending user data entered into a form to be saved, for example. For this purpose, let's have a look at POST requests.
Sending a POST request
A POST request allows us to send data to an API. Let's practice.
Practice!
Head to CodePen Exercise P3CH2a and follow the instructions below.
In this exercise, we are going to send a dummy blog post to an API and then print its response to the DOM.
The API we shall be using has been specifically created for this course. The endpoint we shall be using requires that we send it JSON containing title and content fields, and it shall return an object with a message field and a post object, which in turn will contain our post with an added unique ID. This is a fairly typical basic setup for blog or comment APIs, for example.
We are also going to be using Promises and async/await from now on to fully master asynchronous coding!
Let's start by adding a click listener to our submit button that will prepare our form data. Add a click listener to
submitButton
which blocks default submit behavior and creates an object calledpost
which contains atitle
field and acontent
field with the data from the form.Now we're going to create a function which will accept JSON data as an argument, and set up and send our request. This function will return a Promise so that we can use async/await. Create a new function called
makeRequest()
which acceptsdata
as an argument.Have
makeRequest()
return aPromise
.Within the body of the
Promise
, create a newXMLHttpRequest
object calledrequest
, and open it with the verbPOST
. The URL for this request will be theapi
constant + the endpoint'/create-post'
.Create an
onreadystatechange
function forrequest
. Make sure the code within it will only execute if the request has areadyState
of 4 with anif
statement.The API will return a status of 201 for a successful request. Let's use that fact to populate our
onreadystatechange
function. Set up anif...else
statement to handle successful requests vs. unsuccessful requests.HINT: A request's status is stored in its
status
property.If the request is successful, we want the
Promise
to resolve with the response. If it is not, we want it to reject with the response. The response data will be JSON, but it is sent as a string. We will therefore need to parse it to be able to use it as an object.For a successful request:
resolve(JSON.parse(request.response));
.For an unsuccessful request:
reject(JSON.parse(request.response));
.
Now that our
onreadystatechange
function is ready, we need to send our request. However, with a POST request, we need to set a request header to specify what kind of data we are sending. In this case, we are sending JSON, so add this line after theonreadystatechange
declaration:request.setRequestHeader('Content-Type', 'application/json');
.Now that our request is ready, it's time to send it. Remember, we want to send our data object to the API, so we'll be passing it as an argument to the request's
send()
method. However, we need to stringify it first for it to be properly handled by the server. Add this final line to ourPromise
body:request.send(JSON.stringify(data));
.
Once you've given it a go, watch me code a solution and see how your approach compares:
Our request function is ready. Now it's time to build an async
function to bring everything together.
Practice!
Head to CodePen Exercise P3CH2b and follow the instructions below.
We're going to build an async
function to link our form data to our request function. When making an HTTP request, there is always the possibility that it will fail. We have prepared for this eventuality in our Promise
, causing it to reject if the request status is not 201. But how do we handle this in our async
function? Let's look at that together.
Declare
async function submitFormData(post)
.To handle errors, we
try
our desired code andcatch
the error case. Add atry { }
block and acatch (errorResponse) { }
block.Inside our
try
block, we will create an instance of ourPromise
and then useawait
to store its result. Add the following lines to ourtry
block:const requestPromise = makeRequest(post);const response = await requestPromise;
We know that our API will return an object that looks like this:
{ message: string, post: { id: string, title: string, content: string }}
So after our
await
statement, we know that (if the request is successful), we can use these properties. Add these lines to print our result to the DOM:responseMessage.textContent = response.message;responseTitle.textContent = response.post.title;responseId.textContent = response.post.id;responseContent.textContent = response.post.content;
Now in our
catch
block, we want to handle the case where an error occurs. If the API throws an error, its response will simply be an object like this:{ error: string}
Let's use that to print any error messages to the DOM. Add this line to our
catch
block:responseMessage.textContent = errorResponse.error;
Now all we have to do is call
submitFormData()
from our button event handler, passing it the post object we created earlier. Make a call tosubmitFormData()
just after declaring thepost
variable, and pass it that variable.Now create a post and see what happens!
Once you've given it a go, watch me code a solution and see how your approach compares:
In this example, the API simply sent back an object containing the POST with a unique ID, but you could imagine that it added it to a database, to be shown on a page listing all blog posts, for example.
Let's recap!
In this chapter, we looked at sending POST requests. We looked at how to:
build and prepare a POST request,
add the necessary header,
send data with our request,
use promises and async/await to make our request, handle the response and catch any errors.
In the next chapter, we will dive deeper into the advantages of async/await as we use the response of one request to make a second one.