Now that we understand what an API endpoint is, let’s try interacting with the Cat API directly. Enter an endpoint path below (like /v1/images/search?limit=1
) to see the API response.
Try these examples:
/v1/images/search?limit=1
- Get one random cat image
/v1/images/search?mime_types=gif
- Get a random cat GIF
/v1/breeds
- Get a list of cat breeds
/v1/breeds/siam
- Get information about Siamese cats
The response will be shown in JSON format, which is a common data format used by APIs. JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.
Code
viewof method = Inputs. select (["GET" ], {
label : "HTTP Method" ,
attributes : {
class : "form-select mb-3"
}
})
viewof endpoint = Inputs. text ({
label : "Endpoint path" ,
placeholder : "/v1/images/search?limit=1" ,
value : "/v1/images/search?limit=1" ,
attributes : {
class : "form-control mb-3"
}
})
// Function to make the API request
async function fetchFromApi (method, path) {
const baseUrl = "https://api.thecatapi.com" ;
try {
const response = await fetch (` ${ baseUrl}${ path} ` );
const status = {
code : response. status ,
ok : response. ok ,
text : response. statusText
};
if (! response. ok ) {
throw new Error (`HTTP error! status: ${ response. status } ` );
}
const data = await response. json ();
return { data, status };
} catch (error) {
return {
data : { "Message" : `Error: ${ error. message } ` },
status : {
code : 400 ,
ok : false ,
text : "Bad Request"
}
};
}
}
response = {
const result = await fetchFromApi (method, endpoint);
return result;
}
viewof prettyResponse = {
let content;
if (response. data . Message ) {
content = html `<div class="alert alert-warning m-0"> ${ response. data . Message } </div>` ;
} else {
content = html `<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;"> ${ JSON . stringify (response. data , null , 2 )} </pre>` ;
}
const badgeClass = response. status . ok ? "bg-success" : "bg-danger" ;
const container = html `<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<span>Response</span>
<span class="badge ${ badgeClass} "> ${ response. status . code } ${ response. status . text } </span>
</div>
${ content}
</div>` ;
return container;
}
In fact, with the same structure, we can interact with multiple APIs. Let’s try interacting with The Metropolitan Museum of Art Collection API to get the a list of objects ids from the collection.
Code
viewof methodParts = Inputs. select (["GET" ], {
label : "HTTP Method" ,
attributes : {
class : "form-select mb-3"
}
})
viewof domain = Inputs. text ({
label : "Domain" ,
placeholder : "collectionapi.metmuseum.org" ,
value : "collectionapi.metmuseum.org" ,
attributes : {
class : "form-control mb-3"
}
})
viewof path = Inputs. text ({
label : "Path" ,
placeholder : "/public/collection/v1/search" ,
value : "/public/collection/v1/search" ,
attributes : {
class : "form-control mb-3"
}
})
viewof query = Inputs. text ({
label : "Query parameters" ,
placeholder : "?q=cat" ,
value : "q=cat" ,
attributes : {
class : "form-control mb-3"
}
})
async function fetchFromApiParts (method, domain, path, query) {
try {
const baseUrl = `https:// ${ domain} ` ;
const url = ` ${ baseUrl}${ path} ? ${ query} ` ;
const response = await fetch (url);
const status = {
code : response. status ,
ok : response. ok ,
text : response. statusText
};
if (! response. ok ) {
throw new Error (`HTTP error! status: ${ response. status } ` );
}
const data = await response. json ();
return { data, status };
} catch (error) {
return {
data : { "Message" : `Error: ${ error. message } ` },
status : {
code : 400 ,
ok : false ,
text : "Bad Request"
}
};
}
}
responseParts = {
const result = await fetchFromApiParts (methodParts, domain, path, query);
return result;
}
viewof prettyResponseParts = {
let content;
if (responseParts. data . Message ) {
content = html `<div class="alert alert-warning m-0"> ${ responseParts. data . Message } </div>` ;
} else {
content = html `<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;"> ${ JSON . stringify (responseParts. data , null , 2 )} </pre>` ;
}
const badgeClass = responseParts. status . ok ? "bg-success" : "bg-danger" ;
const container = html `<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<span>Response</span>
<span class="badge ${ badgeClass} "> ${ responseParts. status . code } ${ responseParts. status . text } </span>
</div>
${ content}
</div>` ;
return container;
}
Now, take any ID from the result and use it to get the object details from the API.
Code
viewof methodDetails = Inputs. select (["GET" ], {
label : "HTTP Method" ,
attributes : {
class : "form-select mb-3"
}
})
viewof domainDetails = Inputs. text ({
label : "Domain" ,
placeholder : "collectionapi.metmuseum.org" ,
value : "collectionapi.metmuseum.org" ,
attributes : {
class : "form-control mb-3"
}
})
viewof pathDetails = Inputs. text ({
label : "Path" ,
placeholder : "/public/collection/v1/objects/" ,
value : "/public/collection/v1/objects/" ,
attributes : {
class : "form-control mb-3"
}
})
viewof parameterDetails = Inputs. text ({
label : "Parameter" ,
placeholder : "Write the object id here" ,
value : "570744" ,
attributes : {
class : "form-control mb-3"
}
})
async function fetchFromApiDetails (method, domain, path, parameter) {
try {
const baseUrl = `https:// ${ domain} ` ;
const url = ` ${ baseUrl}${ path}${ parameter} ` ;
const response = await fetch (url);
const status = {
code : response. status ,
ok : response. ok ,
text : response. statusText
};
if (! response. ok ) {
throw new Error (`HTTP error! status: ${ response. status } ` );
}
const data = await response. json ();
return { data, status };
} catch (error) {
return { error : error. message };
}
}
responseDetails = {
const result = await fetchFromApiDetails (methodDetails, domainDetails, pathDetails, parameterDetails);
return result;
}
viewof prettyResponseDetailsContainer = {
let content;
if (responseDetails. data . Message ) {
content = html `<div class="alert alert-warning m-0"> ${ responseDetails. data . Message } </div>` ;
} else {
content = html `<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;"> ${ JSON . stringify (responseDetails. data , null , 2 )} </pre>` ;
}
const badgeClass = responseDetails. status . ok ? "bg-success" : "bg-danger" ;
const container = html `<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<span>Response</span>
<span class="badge ${ badgeClass} "> ${ responseDetails. status . code } ${ responseDetails. status . text } </span>
</div>
${ content}
</div>` ;
return container;
}
And that allows us to retrieve, for instance, the image of the object, that is stored in the primaryImage
field.
Code
viewof primaryImage = {
const primaryImage = responseDetails. status . ok ? responseDetails. data . primaryImageSmall : "https://placehold.co/600x400" ;
if (primaryImage) {
const img = html `<img src=" ${ primaryImage} " alt="Primary Image">` ;
return img;
} else {
return html `<img src="https://placehold.co/600x400" alt="Placeholder">` ;
}
}
Nice! Now, let’s do an exercise to practice what we have learned.