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 ;
}
fetchFromApi = async ƒ (method, path)
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 ;
}
fetchFromApiParts = async ƒ (method, domain, path, query)
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 ;
}
fetchFromApiDetails = async ƒ (method, domain, path, parameter)
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.