Requests
This library exports Quest instances that point to individual APIs. See the Quest documentation for using Quest specifically.
Usage
import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { QueryClientProvider } from '@rhapsody/query-client'
import { api } from '@shared/requests'
function App() {
const { data } = useQuery('example.cache.key', async () => {
const response = await api.get('awesome_endpoint')
return response.data
})
return (
<ul>
{data.map((item) => (
<li>{item}</li>
))}
</ul>
)
}
export const AwesomeApp = () => {
return (
<ThemeProvider>
<QueryClientProvider>
<App />
</QueryClientProvider>
</ThemeProvider>
)
}
The above example uses React Query to manage the network request lifecycle in a React component, but it is not required when using the exports from this package.
Exported Services
| Exported Instance | Production URL | Links |
|---|---|---|
analyticsApi | https://api.salesloft.com/v2/analytics | Repo |
api | https://api.salesloft.com/v2 | Repo |
cerebroApi | https://cerebro.<REGION>.salesloft.com | Repo |
costelloApi | https://deals.salesloft.com | Repo |
emailGatewayApi | https://email-gateway.<REGION>.salesloft.com | Repo |
dialerBackendApi | https://dialer-backend.<REGION>.salesloft.com/api/v2 | Repo |
dialerBackendPrivateApi | https://dialer-backend.<REGION>.salesloft.com | Repo |
goalsApi | https://api.salesloft.com/v2 | Repo |
meetingsApi | https://api.salesloft.com/v2 | Repo |
melodyApi | https://melody.<REGION>.salesloft.com/api | Repo |
melodyRoot | https://melody.<REGION>.salesloft.com | Repo |
noteninjaApi | https://noteninja-web-api.<REGION>.salesloft.com | Repo |
tracerBulletApi | https://tracer-bullet.<REGION>.salesloft.com | Repo |
Services Methods
GET
By passing in a string, we can use the .get() method to retrieve information from a single endpoint. This method returns a promise. It also accepts additional options to modify the request.
import { api } from '@shared/requests'
export const awesomeFetchFunction = async () => {
const response = await api.get('awesome_endpoint')
return response.data
}
export const awesomeFetchWithOptionsFunction = async () => {
const response = await api.get('awesome_endpoint/with_options', {
searchParams: { detailed: true },
})
return response.data
}
POST
By passing in a string and an object containing the information for the .post() method we can create the data on the API. This method returns a promise. It also accepts additional options to modify the request.
import { api } from '@shared/requests'
export const awesomePostFunction = async () => {
const response = await api.post('awesome_endpoint', {
body: {
id: 123,
name: 'Nosferatu',
},
})
return response.data
}
PUT
By passing in a string and an object containing the information for the .put() method we can update the data on the API. This method returns a promise. It also accepts additional options to modify the request.
import { api } from '@shared/requests'
export const awesomePutFunction = async () => {
const userId = 1234
const options = {
json: {
custom_poll_at: true,
},
}
const response = await api.put(`awesome_endpoint/${userId}`, options)
return response.data
}
DELETE
By passing in a string and an object containing the information for the .delete() method we can delete the data on the API. This method returns a promise. It also accepts additional options to modify the request.
import { api } from '@shared/requests'
export const awesomeDeleteFunction = async () => {
const userId = 1234
const response = await api.delete(`awesome_endpoint/${userId}`)
return response.data
}
Get All Pages
This is a function for all the endpoints that can return a total count of pages. It can take an object as a query, with the format key: value. getAllPages only works with the public API.
import React, { useState } from 'react'
import { useAsync } from 'react-use'
import { getAllPages } from '@shared/requests'
const App = () => {
const [totalPages, setTotalPages] = useState(0)
useAsync(async () => {
const pages = await getAllPages('awesome_endpoint', {
field_type: 'something_awesome',
})
setTotalPages(pages)
})
return (
<div>
<span>Total Pages: {totalPages}</span>
</div>
)
}
Testing
If you want to use the functions on your unit test, you need to either spy the call to the function so you can return the data you want or you can also mock the function with some static data, either way, should work, down below are two examples:
Using jest.spyOn
import * as requestService from '@shared/requests'
jest.mock('@shared/requests')
describe('AwesomeComponent', () => {
it('shows an example of how to use jest.spyOn', async () => {
jest
.spyOn(requestService, 'getAllPages')
.mockImplementation(() => Promise.resolve([]))
expect(true).toBe(true)
})
})
Using jest.fn() for mock values
import { api } from '@shared/requests'
beforeEach(() => {
api.get = jest.fn().mockResolvedValue({ data: [] })
})
describe('AwesomeComponent', () => {
it('shows an example of how to use jest.fn', async () => {
// Mount the component or call the service
expect(true).toBe(true)
})
})
Quest Hooks
Quest allows us to provide functions to run before a request is sent to the server or after a response has been returned. This package provides utility hooks to simplify common use cases.
throwIfNotOkHook
By default, Quest does not throw an error on a non-2xx response code. If you would like a Quest instance to throw for non-2xx responses, use the throwIfNotOkHook. This is particularly useful when using React Query as RQ has built-in error handling when errors are thrown.
import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { api, throwIfNotOkHook } from '@shared/requests'
function App() {
const { data, error } = useQuery('example.cache.key', async () => {
const response = await api.get('example', {
hooks: { afterResponse: [throwIfNotOkHook] },
})
return response.data
})
if (error) {
return <p>🛑 An error occurred: {error}</p>
}
return (
<ul>
{data.map((item) => (
<li>{item}</li>
))}
</ul>
)
}