Endpoints

In the terminology of APIs, an endpoint is a URL that specifies the location of a resource on a server. As we saw with the cat API, most of the time you can access the data from an endpoint without requiring any particular software besides a web browser.

However, an API doesn’t just retrieve data, it could also create, update, or delete data. For that reason, we could say that an endpoint is a specific type of URL that allows you to perform a specific action on a resource.

Then, let’s break the pieces of an endpoint into four parts:

The protocol

The protocol is the first part of an endpoint, specifying whether access to the resource is done through HTTP or HTTPS. In simple terms, HTTP is the same protocol used by the web browser to retrieve web pages. The “S” in HTTPS stands for “secure” and it means that the communication between the client and the server is encrypted.

Note

Currently, HTTPS is the de facto standard for APIs, due to enhanced security.

The domain

The second part of an endpoint is the domain name. This means the unique name of the host that provides the resource. In our example, the domain of the cat API is api.thecatapi.com.

Note

The domain name of the API is not necessarily the same as the name of the main website of the API provider. For instance, the domain name of the cat API is api.thecatapi.com, but the main website of the cat API is thecatapi.com.

The path

The third part of an endpoint is the path. This piece of the endpoint specifies the resource we want to access. This could be a specific set of data, for instance, a list of cat breeds, but it could also be an action to be performed, for instance, searching. The path can also specify the version of the API that is being used, for instance, “v1” or “v2”.

In the cat API, the path can be something like /v1/breeds.

Some endpoints can include a resource identifier to retrieve a specific resource, for instance, the path /v1/breeds/ gives as response a list of all cat breeds, and it’s possible to retrieve a specific breed, let’s say “Korat”, by adding the identifier /kora to the path, so the full path would be /v1/breeds/kora.

The query parameters

An endpoint can retrieve lists of data and individual items. It can also perform actions, for instance, searching. The query parameters are the part of endpoints that allows us to explore the data available in the API. This can include multiple parts used to specify the search. Let’s explore this with more detail.

The Cat API has an endpoint to search for cat images. The path of this endpoint is /v1/images/search. If we do a request to this endpoint we will get a random cat image. However, the developers have included a set of parameters that can delimit the search like the size of the image, the type of the image, the format of the response, if the image has a breed, etc. In that case, instead of just having a random cat image, we can retrieve a list of cat images with a size, media type, and with a specific limit. Then, the part of the endpoint will be like this:

search?size=small&mime_types=gif&limit=10

Note that the query parameters are separated from the path by a question mark (?) and they are separated by ampersands (&). Order of the parameters is not important, but using the correct name of the parameter is crucial.

The full endpoint

Now, having all the parts of an endpoint, we can write the full endpoint as follows:

This can be read as follows: “I want to retrieve 5 cat gif images with a small size”.

With this result:

Code
cats = {
  try {
    return await FileAttachment("../_data/cats.json").json();
  } catch (e) {
    console.error("Error loading cats data. This is normal if you're running the book locally.", e);
    return await FileAttachment("../_dev/cats-fallback.json").json()
  }
}

viewof carousel = {
  const container = html`
    <div class="carousel-container">
      <div class="carousel-wrapper"></div>
      <button class="carousel-button prev">←</button>
      <button class="carousel-button next">→</button>
    </div>
  `;
  
  const wrapper = container.querySelector('.carousel-wrapper');
  
  cats.forEach(cat => {
    const img = document.createElement('img');
    img.src = cat.url;
    img.alt = 'Cat image';
    wrapper.appendChild(img);
  });

  let currentIndex = 0;
  const totalImages = cats.length;
  
  function updateCarousel() {
    wrapper.style.transform = `translateX(-${currentIndex * 100}%)`;
  }

  container.querySelector('.next').addEventListener('click', () => {
    currentIndex = (currentIndex + 1) % totalImages;
    updateCarousel();
  });

  container.querySelector('.prev').addEventListener('click', () => {
    currentIndex = (currentIndex - 1 + totalImages) % totalImages;
    updateCarousel();
  });
  
  return container;
}