AJAX with Fetch and CrudCrud

While you’re learning AJAX and Fetch it’s helpful to have a practice REST API to work with. CrudCrud is a service that provides a REST API backend that is customizable to whatever you’re working on.

It doesn’t have a lot of documentation, so here’s a simple guide on how to use it with Fetch.

Resources

In your app you’ll have some resources that you want to save on the backend. They may be posts or tasks or shopping cart items. Or spaceships.

To save them with CrudCrud, you’ll pick a name for your resource (like “spaceships”) and use it with your CrudCrud endpoint. CrudCrud will do all the work to set it up on the backend.

With spaceships it might look something like this:

https://crudcrud.com/api/6258dc47698c4d72/spaceships

You can have multiple resources on your CrudCrud endpoint, maybe like this:

https://crudcrud.com/api/6258dc47698c4d72/spaceships

https://crudcrud.com/api/6258dc47698c4d72/planets

https://crudcrud.com/api/6258dc47698c4d72/wormhole-gates

Naming Best Practices

There are many ways to name your resources, but here are some best practices

  • It should be a noun.
    Ex: spaceships not getSpaceships
  • It should be plural.
    Ex: planets not planet
    (there are some exceptions, such as when there will only ever be one)
  • It should be all lowercase letters.
    Ex: spaceships not Spaceships or SpaceShips
  • It should use dashes in place of spaces.
    Ex: wormhole-gates not wormhole_gates
  • It shouldn’t be shortened.
    Ex: wormhole-gates not wh-gates

Tips

A few things to be aware of:

1)

We’ll save our endpoints in const variables so they’re only written out in one place. Like this:

const API_ENDPOINT = "https://crudcrud.com/api/6258dc47698c4d72";
const SPACESHIPS_ENDPOINT = API_ENDPOINT + "/spaceships";
const PLANETS_ENDPOINT = API_ENDPOINT + "/planets";
const WORMHOLE_GATES_ENDPOINT = API_ENDPOINT + "/wormhole-gates";

2)

Fetch uses promises. That means when we call fetch() it doesn’t wait to get a response back, it immediately returns a promise object. At some point that promise will be fulfilled and make the response available.

If we want to wait until the promise is fulfilled (in this case, meaning the response has come back from the backend), before the code continues, we can use the await keyword.

Any function that uses the await keyword inside needs to be marked as async.

You could also use the .then() method, but in these examples I will use await.

3)

If we log a response from fetch() to the console, it looks something like this:

If we need to get actual JSON data from a response we’ll use the .json() method to parse the body into JSON.

await response.json();

If our response was from a GET request for all the planets, that might give us something like this:

[
    {
        _id: 0,
        name: "Tatooine",
        habitable: true
    },
    {
        _id: 1,
        name: "Dagobah",
        habitable: false
    }
]

4)

When we need to send JSON to our API, we’ll turn it into a string like this:

JSON.stringify(objectOrArrayToStringify)

Stringifying our JSON will turn this:

{
    name: "Dagobah",
    habitable: false
}

Into this:

'{"name":"Dagobah","habitable":false}'

And it’ll be ready to send to our backend.

5)

CrudCrud stores its ids in a property called _id. If you need to access the id of an object, make sure you don’t forget the underscore.

resource._id

Read All

To get a list of resources, make a GET request to the resources endpoint.

fetch(RESOURCES_ENDPOINT)

(We don’t need to specify a method when we’re using Fetch to make a GET request because it will use GET by default.)

For example, we can get the list of planets:

const response = await fetch(PLANETS_ENDPOINT);
const planets = await response.json();

And now our planets variable will have an array of our planet objects.

[
    {
        _id: 0,
        name: "Tatooine",
        habitable: true
    },
    {
        _id: 1,
        name: "Dagobah",
        habitable: false
    }
]

If we haven’t created any planets yet, it will be an empty array: []

Read One

To get one resource, make a GET request to the resources endpoint with the id of the resource on the end of the URL.

fetch(RESOURCES_ENDPOINT + "/" + id)

If we want to get the shapeship with the id of 4, we can ask for it like this:

const response = await fetch(SPACESHIPS_ENDPOINT + "/4");
const razorCrest = await response.json():

This function will get any spaceship from the backend by its id:

const getSpaceshipById = async (spaceshipId) => {
    const resp = await fetch(
        SPACESHIPS_ENDPOINT + "/" + spaceshipId
    )
    return await resp.json();
}

Create

To save a newly created resource to the backend, make a POST request to the resource endpoint.

fetch(RESOURCE_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(newResourceData)
})

The variable newResourceData should be an object with all the properties we want on the new resource.

If we want to create a new planet with this data:

const planetData = {
    name: "Mandalore",
    habitable: true
}

We can create it like this:

const response = await fetch(PLANETS_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(planetData)
})
const mandalore = await response.json();

The variable mandalore will be the newly created planet with the id.

{
    _id: 2,
    name: "Mandalore",
    habitable: true
}

If you need to, you can use that response to update the frontend data with the id. Or you can just refresh the whole list by sending a GET request for all the planets.

Update

To update the data on a resource, make a PUT request to the resources endpoint with the id of the resource on the end of the URL.

fetch(PLANETS_ENDPOINT + "/" + resourceId, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(updatedResourceData)
})

The variable resourceId should be the id of the resource to update.

The variable updatedResourceData should be an object with the updated properties of the resource.

CrudCrud has 2 rules for the object in updatedResourceData.

  1. It cannot have an _id property. This means we cannot just send the updated object. We have to make a copy without the _id property. If we don’t, the request will fail and we’ll get an error.
  2. It must have all the properties of the resource, even properties that are staying the same. Any properties we leave off will be removed from the resource.

Not all backend APIs have those same rules. Each API has its own specific expectations for requests. But CrudCrud will not update the resource correctly if we don’t follow those rules.

If, on the frontend, this planet:

const planet = {
    _id: 7,
    name: "Mustafar",
    habitable: true
}

Has been updated and the habitable property has been set to false:

const planet = {
    _id: 7,
    name: "Mustafar",
    habitable: false
}

We can save that to the backend like this:

const planetWithoutId = {
    name: planet.name,
    habitable: planet.habitable
}
const response = await fetch(
    PLANETS_ENDPOINT + "/" + planet._id, 
    {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(planetWithoutId)
    }
)

(We don’t need the .json() method here because CrudCrud doesn’t return any data from a PUT request.)

If we left off the name property from planetWithoutId then the name would get removed and Mustafar would look like this:

{
    _id: 7,
    habitable: false
}

So make sure to include all the properties, even properties that are staying the same.

Cool Tip

We can make a copy of an object without one property using object destructuring and spread syntax. It looks like this:

const { _id, ...copyWithoutId } = objectToCopyWithoutId

I didn’t use that method above for clarity, but it can save a lot of hassle with bigger objects.

Delete

To delete a resource, make a DELETE request to the resources endpoint with the id of the resource on the end of the URL.

fetch(PLANETS_ENDPOINT + "/" + resourceId, {
    method: "DELETE"
})

We don’t need headers or a body because there’s no data to send.

If we want to delete this planet:

const planet = {
    _id: 9,
    name: Alderaan,
    habitable: true
}

We can do that like this:

const response = await fetch(
    PLANETS_ENDPOINT + "/" + planet._id, 
    { method: "DELETE" }
)

(We don’t need the .json() method here because CrudCrud doesn’t return any data from a DELETE request.)

Conclusion

CrudCrud is a handy resource for practicing with AJAX, but it doesn’t have a lot of documentation. Hopefully with the help of this guide you can start using CrudCrud in your own practice projects.

Leave a Reply

Your email address will not be published. Required fields are marked *