Fetching Data
📚 Table of Contents |
---|
API 101 |
HTTP Methods |
fetch() |
- now that we know what promises are, we can start to do some really cool shit
- I'm going to step on the gas a little here. I'm still going to try and spell things out simply but we are also going to pick up the pace
- at their core, most modern apps, websites and SaaS platforms perform CRUD (Create Read Update Delete) operations from a UI (frontend) on a database (backend) via an API (Application Programming Interface)
API 101
- API's are the modern way frontends and backends communicate in web development
- in this context, API's are usually accessible through a URL like a regular website, i.e.
https://api.example.com
https://api.example.com
would be considered the base URL. from there the backend devs will give specific paths which are known as endpoints, i.e.https://api.example.com/users
, which would presumably give you access to the users in the database- the API endpoints will give you access to perform CRUD operations on the data and through HTTP protocalls
HTTP Methods
these are the CRUD methods that you can use
- GET: gets your data so you can Read it
- POST: sends or posts data so you can Create it
- PUT: replaces data, or puts an Update through
- DELETE: Deletes data
fetch()
fetch()
is super important. it is the modern way to fetch resources asynchronously- fun fact: for context, the old way is known as AJAX (asynchronous JavaScript and XML).
- when I say fetching resources, I mean it can work with local files, can include requests that involve cookies, can work with streaming responses, image and file uploads but most importantly it is used to hit API endpoints
fetch()
is a method / function that returns a promise once the response is available- the basic syntax is:
fetch(resource, options);
- the
options
are optional 🙃 (more on that in a minute) - the
resource
is the URL, so you can usefetch()
like this:
fetch("https://api.example.com/users");
- without
options
provided,fetch()
will by default perform a GET request and download the resources from the URL fetch()
returns aresponse
object. theresponse
is important because obviously that is where the data that you need is going to be, but before you access the data, theresponse
object has this cool feature where you can check the status of the response to make sure everything is working. you do this by literally checkingresponse.ok
response.ok
returns a boolean (true or false) if the request is good or not. good meaning it received an HTTP status code (opens in a new tab) in the 200's. you can check the specific status code too by checkingresponse.status
- if you have a good response, you use your data with
response.json()
..json()
on theresponse
object will read the entire response, parse the body text as JSON and return a promise that resolves witht he result - ok that was a lot of explaining, I think it makes a little more sense actually coding this out:
async function fetchData() {
const response = await fetch("https://api.example.com/users");
if (response.ok) {
const data = await response.json();
console.log(data);
}
}
- that
console.log()
would show you the list of users that you just got back from the API endpoint. notice theawait
keyword before the promises - the
if (response.ok)
is also of course optional but its good practice to use it. actually, it is generally considered good practice to use atry / catch
here to account for bad responses and errors. this is pretty mucht the same thing but even better (going to switch to an arrow function for style 😎):
const fetchUsers = async () => {
try {
const response = await fetch("https://api.example.com/users");
if (!response.ok) {
throw new Error("Failed to fetch users");
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Error:", error);
}
};
- with me so far? if the info above is a little hazy for you, we're going to see this in action with a real API in the next exercise, so sit tight. before we get to using a real API I want to show a few more things
- lets mock a POST request to the same example API. POST requests send info to the API, so you would need to do this if you were creating a new user in the database
- this is when we need to use the
options
infetch()
- options are passed in as an object, so we need to use curly braces (
{}
) and then define the data we are sending inkey: value
pairs. we also have to include the HTTPmethod
,headers
and thebody
- lets create a new function to create a user that will take in userData (maybe from a sign up form or something) and send that userData to the API via a POST request
const createUser = async (userData) => {
try {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error("Failed to create user");
}
const data = await response.json();
console.log("User created:", data);
} catch (error) {
console.error("Error:", error);
}
};
- looks kind of intense but if you break it down, the only thing that really changed are the
options
- the
method
is obviously the type of the HTTP method; also it is conventional to use all caps for that - the
headers
section is where you define the type of data you are sending, also notice you send this as an object ({}
)."Content-Type": "application/json"
is pretty much boilerplate for this type of stuff. if you want to send a file or an image or something you would useContent-Type": multipart/form-data
headers
is important because this is also where you will put authorization information. most APIs are not available to the public so you usually need to provide an API key to access it, usually even with GET requests. Bearer tokens are pretty common, you would include one like this:
- the
const createUser = async (userData) => {
try {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${anAPIkey}`,
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error("Failed to create user");
}
const data = await response.json();
console.log("User created:", data);
} catch (error) {
console.error("Error:", error);
}
};
// make sure "Authorization" is in quotes to be a string, my editor keeps removing them for some reason 🫠
-
in the
body
we send the userData (or whatever you are sending to the API). JSON.stringify() (opens in a new tab) is standard for sending JSON data to an API endpoint. the body of a fetch request needs to be a string when sending JSON data,JSON.stringify()
is used to serialize the userData object into a JSON-formatted string. this is important because the HTTP protocol can't directly transmit JavaScript objects; it sends strings over the network -
to perform PUT and DELETE requests, you pretty much only have to change the HTTP method