# Reaching Out To The Web

## HTTP Requests in React

1. `npm install axios` and import it: `import axios from "axios";`.
2. Create a `Promise` object using `axios.get`, `axios.post`, etc.
3. Chain `.then()` and `.catch()` for handling `response` and `error` respectively.

## Adding Interceptors

It's very common to handle errors and HTTP requests locally within a component. For example, a component may have a `this.state.error` to track if something breaks during a `.catch()`. Then, the UI will render a message to the user if `this.state.error` has content.

However, on top of local HTTP request and error handling, you can use **interceptors** that add global customization to your HTTP requests and errors.

Think of interceptors as **middle men** that are passed the `request`, `response`, or `error` object to do custom work. Then you pass the objects forward for local handling.

```js
// In a global file like index.js, add this...

// ** FOR REQUESTS **
const reqInterceptor = axios.interceptors.request.use(request => {
  // Do something before request is sent
  // COMMON PRACTICE: Add authorization headers

  return request; // pushes forward request for local handling
}, error => {
  // Do something with error
  return Promise.reject(error); // pushes forwards error for local handling
});

// ** FOR RESPONSES **
const resInterceptor = axios.interceptors.response.use(response => {
  // Do something with response data
  return response; // pushes forward response for local handling
}, error => {
  // Do something with error
  return Promise.reject(error); // pushes forwards error for local handling 
});
```

## Removing Interceptors

To eject/remove an interceptor, simply use:

```js
const reqInterceptor = axios.interceptors.request.use(...)
const resInterceptor = axios.interceptors.response.use(...)

// ** TO EJECT INTERCEPTOR **
axios.interceptors.request.eject(reqInterceptor);
axios.interceptors.response.eject(resInterceptor);
```

**Note**: It's a good idea to add `eject` as part of a **cleanup** function like `componentWillUnmount` or the cleanup callback in `useEffect`.

## Global Configuration

`axios` and other request libraries give you access to a `defaults` object for configuring defaults.

```js
// In a global file like index.js...

axios.defaults.baseURL = "https://api.com/v1"; // Base URL for API endpoint
axios.defaults.headers.common // For headers that apply to all requests
axios.defaults.headers.post // For headers specifically for POST requests
```

## Axios Instances

Sometimes your `axios` configuration needs to be different for different situations. For this, you can set up half measures known as an **instance**.

```js
import axios from "axios";

const axiosInstance = axios.create({
  baseURL: "https://api.com/v2"
});

// axiosInstance.interceptors works too
// axiosInstance.defaults works too

export default axiosInstance;
```

Now you can use `axiosInstance` for HTTP requests and even create multiple instances.

**Pro tip**: Instances work because of prototypal inheritance! You're overriding default behaviour in the global `axios` object. If you don't override, `axiosInstance` will inherit `axios` properties.

## Error Handling HOC

Using interceptors, we can create a higher-order component that handles any `axios` errors and displays them. Here's the basic code:

```js
const withErrorHandler = (WrappedComponent, axios) => {
  return props => {
    // Create error state
    const [error, setError] = useState(null)

    // On mount, add axios interceptors to axios instance USED BY WrappedComponent
    useEffect(() => {
      axios.interceptors.request.use(req => {
        setError(null) // <= Reset error state on new request
        return req
      })

      axios.interceptors.response.use(res => res, err => {
        setError(err) // <= Set error state
        return Promise.reject(err)
      })
    }, [setError])

    return (
      <>
        <Modal {/* <= We're using a modal to display the error */}
          show={error ? true : false}
        >
          {error ? error.message : null}
        <Modal />
        <WrappedComponent {...props} /> {/* <= Passing props down to component */}
      </>
    )
  }
}
```

Then in your actual component, add the HOC:

```js
export default withErrorHandler(MyComponent, axios)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.danfitz.com/javascript/reactcompleteguide/8-reaching-out-to-the-web.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
