#Day21 - How to use requests to interact with APIs in Python
Published: 2021-04-11 03:17:49

## Want a list of cool APIs to use for your next project?

<br>
Today we will be working with the requests libraries and use it to make requests to some public APIS. I have also included a few resources that have a list of cool APIs. This article will not talk about what an API is or the different status codes. Some familiarity with APIs is expected. We will be discussing the following

- Making a simple GET Request
- The Response Object
- Making a Request with parameters
- Make a GET Request to a secured endpoint
- Making a POST Request
- APIs you can use for your next project

### Make a GET Request
Starting off with the basics, we will try to make a request to the publicly available  [Cat Facts API](https://alexwohlbruck.github.io/cat-facts/) 

We will be making a request to the following endpoint 
```
https://cat-fact.herokuapp.com
```
The following code-snippet makes a request to the endpoint
```python
import requests

url = "https://cat-fact.herokuapp.com"
response = requests.get(url)

print(response)
print(type(response))
```

You should see the following output
```
<Response [200]>
<class 'requests.models.Response'>
```
The get() function returned a Response Object. We will talk about the response object in the next section.

Let's try making another GET request. This time we will make a request to the  [Dog Facts API](https://dukengn.github.io/Dog-facts-API/). This is the endpoint we will making the request to 
```
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs/all
```
Below is the code snippet
```python
url = "https://dog-facts-api.herokuapp.com/api/v1/resources/dogs/all"
response = requests.get(url)

print(response)
print(type(response))
```
You should see a similar output as the previous output. So how do we use the Response Object to access the data we need?

### Response Object
Let's continue working with Dog Facts API. The following snippet of code will help us introspect the returned Response object
```python
print(dir(response))
```
You will see a list with a bunch of stuff. Focus on the last few.
#### status_code
This contains the status code of our request. For a successful GET request, it should be 200.
```python
print(response.status_code)
'''
OUTPUT
200
'''
```
#### url
This contains the URL of the response.
```python
print(response.url)
'''
OUTPUT
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs/all
'''
```
#### ok
This is true if the status code is less than 400
```python
print(response.ok)
'''
OUTPUT
True
'''
```
#### json
This returns a JSON object of the result. Basically the data we want to access. If the data returned by the endpoint is not in a JSON format, it will raise an error. Most API endpoints usually return data in a JSON format, it's good practice.
```python
print(response.json()[0])
'''
OUTPUT
{'fact': 'All dogs can be traced back 40 million years ago to a weasel-like animal called the Miacis which dwelled in trees and dens. The Miacis later evolved into the Tomarctus, a direct forbear of the genus Canis, which includes the wolf and jackal as well as the dog.'}
'''
```
I am only displaying the first fact in the list but you can try it out on your own without the indexing.

#### text
This contains the result in Unicode format, i.e a string object. The output might look similar to the one returned by json() but if you use type() to inspect the type of the returned data, you'll notice it is a string
```python
print(response.text)
print(type(response.text))
'''
OUTPUT
  {
    "fact": "Fifty-eight percent of people put pets in family and holiday portraits."
  }, 
  {
    "fact": "There are only 350 Cisky Terriers in the world, possibly making it the rarest breed."
  }, 
  .............
  <class 'str'>
'''
```
I have truncated the output since it was too long.

### Making a Request with parameters
Some endpoints accept parameters. The Dog Facts API accepts a couple of parameters
- num: to specify the number of facts you want to receive
- index: to specify the index of the fact you are targeting
There are a couple of ways to include parameters in your request

#### Including parameter in URL
You can include the parameter in your URL with a ""?parameter=value"". Be careful to use the base URL. In our case, the base URL is the following
```
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs
```
Our URL with the parameter included would be the following

```
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=2
```
Below is the code to make a request to get 2 facts.

```python
url = "https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=2"
response = requests.get(url)

print(len(response.json()))
'''
OUTPUT
2
'''
```
#### Including a parameters object in the get request
Another way would be to set the "params" argument in the get() function to our parameter.
Below is the code
```python
import requests

url = "https://dog-facts-api.herokuapp.com/api/v1/resources/dogs"
param_obj = {"number" : 2}
response = requests.get(url, params=param_obj)

print(len(response.json()))
print(response.url)
'''
OUTPUT
2
https://dog-facts-api.herokuapp.com/api/v1/resources/dogs?number=2
'''
```
As you can see, "response.url" contains the URL with the parameter included.

 
### Make a GET Request to a secured endpoint
Most APIs are secured to prevent malicious requests. An API key is needed whenever you make a request to the API. We will be working with [Cats API](https://docs.thecatapi.com/). This is different from the first Cat Facts API we used, this is secured. Before proceeding, get your API key from [here](https://thecatapi.com/).

We should follow best practices when dealing with API keys. The API key must not directly be used in your python file. It must either be used as an environment variable or stored in a .env file. The API key must be loaded in the Python file, so as to hide it from others.
- Create a file named ".env" in the same folder as your python file and paste the following
```python
API_KEY = "YOUR API KEY HERE"
```
Add your API Key as the string
- Install the following library
```shell
pip install python-dotenv
```
- Load the API Key

```python
import os
import dotenv

dotenv.load_dotenv()
API_KEY = os.getenv("API_KEY")
print(API_KEY)
```

Now let's add the API key while making the requests. Some API let you add it as a parameter (refer to the specific API's documentation for more instructions. Another way is to include it as a header while using the get() function
```python
import requests
import os
import dotenv

dotenv.load_dotenv()
API_KEY = os.getenv("API_KEY")
headers = {'x-api-key': API_KEY}
url = "https://thecatapi.com/v1/images"
response = requests.get(url, headers = headers)

print(response.status_code)
```
Again, the key in the header's object can vary from one API to another. But the general format of making a request to a secured endpoint remains the same.

###  Making a POST Request
Making a Post request is similar to making a get request. Instead of the get() method, we used the post() method. We will make a POST request to the following [API](https://jsonplaceholder.typicode.com/).
The following endpoint supports a POST Request
```
https://jsonplaceholder.typicode.com/posts
```
A post request requires some payload/data to be included in the request. The post() method has a parameter called "data" and our object can be passed as an argument to that.
```python
import requests

url = "https://jsonplaceholder.typicode.com/posts"
data = {
    "userId": 1,
    "title": "#DAY21",
    "body": "Today is #DAY21 of #100daysofcode"
  }
response = requests.post(url)

print(response.status_code)
```
- If the POST request was successful, you should get a status_code of 201
- Ensure your data object follows the proper documentation as provided in the documentation.

### APIs you can use for your next project
Below is a list of resources with a list of APIs (A list of lists)
- https://betterprogramming.pub/a-curated-list-of-100-cool-and-fun-public-apis-to-inspire-your-next-project-7600ce3e9b3
- https://github.com/public-apis/public-apis
- https://publicapis.sznm.dev/