Add frontend API client (#242)

* Frontend API client

* Test

* CR updates
This commit is contained in:
KoalaSat
2022-09-16 16:16:33 +02:00
committed by GitHub
parent b6edc27e6e
commit c770d231d1
9 changed files with 157 additions and 222 deletions

View File

@ -31,6 +31,7 @@ import { pn, amountToString } from '../utils/prettyNumbers';
import PaymentText from './PaymentText'; import PaymentText from './PaymentText';
import DepthChart from './Charts/DepthChart'; import DepthChart from './Charts/DepthChart';
import RobotAvatar from './Robots/RobotAvatar'; import RobotAvatar from './Robots/RobotAvatar';
import { apiClient } from '../services/api/index';
// Icons // Icons
import { BarChart, FormatListBulleted, Refresh } from '@mui/icons-material'; import { BarChart, FormatListBulleted, Refresh } from '@mui/icons-material';
@ -51,8 +52,7 @@ class BookPage extends Component {
getOrderDetails(type, currency) { getOrderDetails(type, currency) {
this.props.setAppState({ bookLoading: true }); this.props.setAppState({ bookLoading: true });
fetch('/api/book' + '?currency=' + currency + '&type=' + type) apiClient.get('/api/book?currency=' + currency + '&type=' + type)
.then((response) => response.json())
.then((data) => .then((data) =>
this.props.setAppState({ this.props.setAppState({
bookNotFound: data.not_found, bookNotFound: data.not_found,

View File

@ -18,6 +18,7 @@ import {
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import Flags from 'country-flag-icons/react/3x2'; import Flags from 'country-flag-icons/react/3x2';
import { Link as LinkRouter } from 'react-router-dom'; import { Link as LinkRouter } from 'react-router-dom';
import { apiClient } from '../services/api';
// Icons // Icons
import BarChartIcon from '@mui/icons-material/BarChart'; import BarChartIcon from '@mui/icons-material/BarChart';
@ -71,8 +72,7 @@ class BottomBar extends Component {
getInfo() { getInfo() {
this.setState(null); this.setState(null);
fetch('/api/info/') apiClient.get('/api/info/')
.then((response) => response.json())
.then( .then(
(data) => (data) =>
this.setState(data) & this.setState(data) &
@ -122,16 +122,9 @@ class BottomBar extends Component {
showRewardsSpinner: true, showRewardsSpinner: true,
}); });
const requestOptions = { apiClient.post('/api/reward/', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
invoice: rewardInvoice, invoice: rewardInvoice,
}), }).then(
};
fetch('/api/reward/', requestOptions)
.then((response) => response.json())
.then(
(data) => (data) =>
this.setState({ this.setState({
badInvoice: data.bad_invoice, badInvoice: data.bad_invoice,
@ -147,13 +140,7 @@ class BottomBar extends Component {
}; };
handleSetStealthInvoice = (wantsStealth) => { handleSetStealthInvoice = (wantsStealth) => {
const requestOptions = { apiClient.put('/api/stealth/', { wantsStealth })
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({ wantsStealth }),
};
fetch('/api/stealth/', requestOptions)
.then((response) => response.json())
.then((data) => this.props.setAppState({ stealthInvoices: data.wantsStealth })); .then((data) => this.props.setAppState({ stealthInvoices: data.wantsStealth }));
}; };

View File

@ -29,6 +29,7 @@ import currencyDict from '../../../../static/assets/currencies.json';
import PaymentText from '../../PaymentText'; import PaymentText from '../../PaymentText';
import getNivoScheme from '../NivoScheme'; import getNivoScheme from '../NivoScheme';
import median from '../../../utils/match'; import median from '../../../utils/match';
import { apiClient } from '../../../services/api/index';
interface DepthChartProps { interface DepthChartProps {
bookLoading: boolean; bookLoading: boolean;
@ -62,8 +63,7 @@ const DepthChart: React.FC<DepthChartProps> = ({
useEffect(() => { useEffect(() => {
if (Object.keys(limits).length === 0) { if (Object.keys(limits).length === 0) {
fetch('/api/limits/') apiClient.get('/api/limits/')
.then(async (response) => await response.json())
.then((data) => { .then((data) => {
setAppState({ limits: data }); setAppState({ limits: data });
}); });

View File

@ -37,6 +37,7 @@ import { LocalizationProvider, TimePicker } from '@mui/x-date-pickers';
import DateFnsUtils from '@date-io/date-fns'; import DateFnsUtils from '@date-io/date-fns';
import { Link as LinkRouter } from 'react-router-dom'; import { Link as LinkRouter } from 'react-router-dom';
import { StoreTokenDialog, NoRobotDialog } from './Dialogs'; import { StoreTokenDialog, NoRobotDialog } from './Dialogs';
import { apiClient } from '../services/api';
import FlagWithProps from './FlagWithProps'; import FlagWithProps from './FlagWithProps';
import AutocompletePayments from './AutocompletePayments'; import AutocompletePayments from './AutocompletePayments';
@ -104,8 +105,7 @@ class MakerPage extends Component {
getLimits() { getLimits() {
this.setState({ loadingLimits: true }); this.setState({ loadingLimits: true });
fetch('/api/limits/') apiClient.get('/api/limits/')
.then((response) => response.json())
.then((data) => .then((data) =>
this.setState({ this.setState({
limits: data, limits: data,
@ -303,10 +303,7 @@ class MakerPage extends Component {
handleCreateOfferButtonPressed = () => { handleCreateOfferButtonPressed = () => {
this.state.amount == null ? this.setState({ amount: 0 }) : null; this.state.amount == null ? this.setState({ amount: 0 }) : null;
const requestOptions = { const body = {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
type: this.state.type, type: this.state.type,
currency: this.state.currency, currency: this.state.currency,
amount: this.state.has_range ? null : this.state.amount, amount: this.state.has_range ? null : this.state.amount,
@ -322,10 +319,8 @@ class MakerPage extends Component {
escrow_duration: this.state.escrowDuration, escrow_duration: this.state.escrowDuration,
bond_size: this.state.bondSize, bond_size: this.state.bondSize,
bondless_taker: this.state.allowBondless, bondless_taker: this.state.allowBondless,
}),
}; };
fetch('/api/make/', requestOptions) apiClient.post('/api/make/', body)
.then((response) => response.json())
.then( .then(
(data) => (data) =>
this.setState({ badRequest: data.bad_request }) & this.setState({ badRequest: data.bad_request }) &

View File

@ -54,6 +54,7 @@ import { getCookie } from '../utils/cookies';
import { pn } from '../utils/prettyNumbers'; import { pn } from '../utils/prettyNumbers';
import { copyToClipboard } from '../utils/clipboard'; import { copyToClipboard } from '../utils/clipboard';
import { getWebln } from '../utils/webln'; import { getWebln } from '../utils/webln';
import { apiClient } from '../services/api';
class OrderPage extends Component { class OrderPage extends Component {
constructor(props) { constructor(props) {
@ -122,8 +123,7 @@ class OrderPage extends Component {
getOrderDetails = (id) => { getOrderDetails = (id) => {
this.setState({ orderId: id }); this.setState({ orderId: id });
fetch('/api/order' + '?order_id=' + id) apiClient.get('/api/order/?order_id=' + id)
.then((response) => response.json())
.then(this.orderDetailsReceived); .then(this.orderDetailsReceived);
}; };
@ -185,17 +185,10 @@ class OrderPage extends Component {
}; };
sendWeblnInvoice = (invoice) => { sendWeblnInvoice = (invoice) => {
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.state.orderId, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'update_invoice', action: 'update_invoice',
invoice, invoice,
}), }).then((data) => this.completeSetState(data));
};
fetch('/api/order/' + '?order_id=' + this.state.orderId, requestOptions)
.then((response) => response.json())
.then((data) => this.completeSetState(data));
}; };
// Countdown Renderer callback with condition // Countdown Renderer callback with condition
@ -429,16 +422,10 @@ class OrderPage extends Component {
takeOrder = () => { takeOrder = () => {
this.setState({ loading: true }); this.setState({ loading: true });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.state.orderId, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'take', action: 'take',
amount: this.state.takeAmount, amount: this.state.takeAmount,
}), })
};
fetch('/api/order/' + '?order_id=' + this.state.orderId, requestOptions)
.then((response) => response.json())
.then((data) => this.handleWebln(data) & this.completeSetState(data)); .then((data) => this.handleWebln(data) & this.completeSetState(data));
}; };
@ -454,16 +441,9 @@ class OrderPage extends Component {
handleClickConfirmCancelButton = () => { handleClickConfirmCancelButton = () => {
this.setState({ loading: true }); this.setState({ loading: true });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.state.orderId, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'cancel', action: 'cancel',
}), }).then(() => this.getOrderDetails(this.state.orderId) & this.setState({ status: 4 }));
};
fetch('/api/order/' + '?order_id=' + this.state.orderId, requestOptions)
.then((response) => response.json())
.then(() => this.getOrderDetails(this.state.orderId) & this.setState({ status: 4 }));
this.handleClickCloseConfirmCancelDialog(); this.handleClickCloseConfirmCancelDialog();
}; };
@ -561,16 +541,9 @@ class OrderPage extends Component {
}; };
handleClickConfirmCollaborativeCancelButton = () => { handleClickConfirmCollaborativeCancelButton = () => {
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.state.orderId, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'cancel', action: 'cancel',
}), }).then(() => this.getOrderDetails(this.state.orderId) & this.setState({ status: 4 }));
};
fetch('/api/order/' + '?order_id=' + this.state.orderId, requestOptions)
.then((response) => response.json())
.then(() => this.getOrderDetails(this.state.orderId) & this.setState({ status: 4 }));
this.handleClickCloseCollaborativeCancelDialog(); this.handleClickCloseCollaborativeCancelDialog();
}; };

View File

@ -33,6 +33,7 @@ import Chat from './EncryptedChat';
import TradeSummary from './TradeSummary'; import TradeSummary from './TradeSummary';
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import { copyToClipboard } from '../utils/clipboard'; import { copyToClipboard } from '../utils/clipboard';
import { apiClient } from '../services/api';
// Icons // Icons
import PercentIcon from '@mui/icons-material/Percent'; import PercentIcon from '@mui/icons-material/Percent';
@ -132,16 +133,9 @@ class TradeBox extends Component {
}; };
handleClickAgreeDisputeButton = () => { handleClickAgreeDisputeButton = () => {
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'dispute', action: 'dispute',
}), }).then((data) => this.props.completeSetState(data));
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then((data) => this.props.completeSetState(data));
this.handleClickCloseConfirmDispute(); this.handleClickCloseConfirmDispute();
}; };
@ -486,16 +480,9 @@ class TradeBox extends Component {
handleClickPauseOrder = () => { handleClickPauseOrder = () => {
this.props.completeSetState({ pauseLoading: true }); this.props.completeSetState({ pauseLoading: true });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'pause', action: 'pause',
}), }).then((data) => this.props.getOrderDetails(data.id));
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then((data) => this.props.getOrderDetails(data.id));
}; };
showMakerWait = () => { showMakerWait = () => {
@ -639,17 +626,10 @@ class TradeBox extends Component {
handleClickSubmitInvoiceButton = () => { handleClickSubmitInvoiceButton = () => {
this.setState({ badInvoice: false }); this.setState({ badInvoice: false });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'update_invoice', action: 'update_invoice',
invoice: this.state.invoice, invoice: this.state.invoice,
}), }).then(
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then(
(data) => (data) =>
this.setState({ badInvoice: data.bad_invoice }) & this.props.completeSetState(data), this.setState({ badInvoice: data.bad_invoice }) & this.props.completeSetState(data),
); );
@ -676,18 +656,11 @@ class TradeBox extends Component {
handleClickSubmitAddressButton = () => { handleClickSubmitAddressButton = () => {
this.setState({ badInvoice: false }); this.setState({ badInvoice: false });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'update_address', action: 'update_address',
address: this.state.address, address: this.state.address,
mining_fee_rate: Math.max(1, this.state.miningFee), mining_fee_rate: Math.max(1, this.state.miningFee),
}), }).then(
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then(
(data) => (data) =>
this.setState({ badAddress: data.bad_address }) & this.props.completeSetState(data), this.setState({ badAddress: data.bad_address }) & this.props.completeSetState(data),
); );
@ -703,17 +676,10 @@ class TradeBox extends Component {
handleClickSubmitStatementButton = () => { handleClickSubmitStatementButton = () => {
this.setState({ badInvoice: false }); this.setState({ badInvoice: false });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'submit_statement', action: 'submit_statement',
statement: this.state.statement, statement: this.state.statement,
}), }).then(
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then(
(data) => (data) =>
this.setState({ badStatement: data.bad_statement }) & this.props.completeSetState(data), this.setState({ badStatement: data.bad_statement }) & this.props.completeSetState(data),
); );
@ -1213,30 +1179,16 @@ class TradeBox extends Component {
} }
handleClickConfirmButton = () => { handleClickConfirmButton = () => {
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'confirm', action: 'confirm',
}), }).then((data) => this.props.completeSetState(data));
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then((data) => this.props.completeSetState(data));
}; };
handleRatingUserChange = (e) => { handleRatingUserChange = (e) => {
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'rate_user', action: 'rate_user',
rating: e.target.value, rating: e.target.value,
}), }).then((data) => this.props.completeSetState(data));
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then((data) => this.props.completeSetState(data));
}; };
handleRatingRobosatsChange = (e) => { handleRatingRobosatsChange = (e) => {
@ -1245,17 +1197,10 @@ class TradeBox extends Component {
} }
this.setState({ rating_platform: e.target.value }); this.setState({ rating_platform: e.target.value });
const requestOptions = { apiClient.post('/api/order/?order_id=' + this.props.data.id, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
action: 'rate_platform', action: 'rate_platform',
rating: e.target.value, rating: e.target.value,
}), }).then((data) => this.props.completeSetState(data));
};
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
.then((response) => response.json())
.then((data) => this.props.completeSetState(data));
}; };
showFiatSentButton() { showFiatSentButton() {
@ -1355,10 +1300,7 @@ class TradeBox extends Component {
handleRenewOrderButtonPressed = () => { handleRenewOrderButtonPressed = () => {
this.setState({ renewLoading: true }); this.setState({ renewLoading: true });
const requestOptions = { const body = {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
type: this.props.data.type, type: this.props.data.type,
currency: this.props.data.currency, currency: this.props.data.currency,
amount: this.props.data.has_range ? null : this.props.data.amount, amount: this.props.data.has_range ? null : this.props.data.amount,
@ -1373,10 +1315,8 @@ class TradeBox extends Component {
escrow_duration: this.props.data.escrow_duration, escrow_duration: this.props.data.escrow_duration,
bond_size: this.props.data.bond_size, bond_size: this.props.data.bond_size,
bondless_taker: this.props.data.bondless_taker, bondless_taker: this.props.data.bondless_taker,
}),
}; };
fetch('/api/make/', requestOptions) apiClient.post('/api/make/', body)
.then((response) => response.json())
.then( .then(
(data) => (data) =>
this.setState({ badRequest: data.bad_request }) & this.setState({ badRequest: data.bad_request }) &

View File

@ -27,6 +27,7 @@ import { genKey } from '../utils/pgp';
import { getCookie, writeCookie, deleteCookie } from '../utils/cookies'; import { getCookie, writeCookie, deleteCookie } from '../utils/cookies';
import { saveAsJson } from '../utils/saveFile'; import { saveAsJson } from '../utils/saveFile';
import { copyToClipboard } from '../utils/clipboard'; import { copyToClipboard } from '../utils/clipboard';
import { apiClient } from '../services/api/index';
class UserGenPage extends Component { class UserGenPage extends Component {
constructor(props) { constructor(props) {
@ -63,11 +64,8 @@ class UserGenPage extends Component {
const strength = tokenStrength(token); const strength = tokenStrength(token);
const refCode = this.refCode; const refCode = this.refCode;
const requestOptions = genKey(token).then(function (key) { const requestBody = genKey(token).then(function (key) {
return { return {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify({
token_sha256: sha256(token), token_sha256: sha256(token),
public_key: key.publicKeyArmored, public_key: key.publicKeyArmored,
encrypted_private_key: key.encryptedPrivateKeyArmored, encrypted_private_key: key.encryptedPrivateKeyArmored,
@ -75,15 +73,11 @@ class UserGenPage extends Component {
counts: strength.counts, counts: strength.counts,
length: token.length, length: token.length,
ref_code: refCode, ref_code: refCode,
}),
}; };
}); });
console.log(requestOptions); requestBody.then((body) =>
apiClient.post('/api/user/', body)
requestOptions.then((options) =>
fetch('/api/user/', options)
.then((response) => response.json())
.then((data) => { .then((data) => {
console.log(data) & console.log(data) &
this.setState({ this.setState({
@ -127,11 +121,7 @@ class UserGenPage extends Component {
}; };
delGeneratedUser() { delGeneratedUser() {
const requestOptions = { apiClient.delete('/api/user')
method: 'DELETE',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
};
fetch('/api/user', requestOptions).then((response) => response.json());
deleteCookie('sessionid'); deleteCookie('sessionid');
deleteCookie('robot_token'); deleteCookie('robot_token');

View File

@ -0,0 +1,40 @@
import { ApiClient } from "../api"
import { getCookie } from '../../../utils/cookies';
class ApiWebClient implements ApiClient {
private getHeaders: () => HeadersInit = () => {
return { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') || "" }
}
public post: (path: string, body: object) => Promise<object> = (path, body) => {
const requestOptions = {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify(body),
};
return fetch(path, requestOptions).then((response) => response.json())
}
public put: (path: string, body: object) => Promise<object> = (path, body) => {
const requestOptions = {
method: 'PUT',
headers: this.getHeaders(),
body: JSON.stringify(body),
};
return fetch(path, requestOptions).then((response) => response.json())
}
public delete: (path: string) => Promise<object> = (path) => {
const requestOptions = {
method: 'DELETE',
headers: this.getHeaders(),
};
return fetch(path, requestOptions).then((response) => response.json())
}
public get: (path: string) => Promise<object> = (path) => {
return fetch(path).then((response) => response.json())
}
}
export default ApiWebClient

View File

@ -0,0 +1,10 @@
import ApiWebClient from './ApiWebClient'
export interface ApiClient {
post: (path: string, body: object) => Promise<object>
put: (path: string, body: object) => Promise<object>
get: (path: string) => Promise<object>
delete: (path: string) => Promise<object>
}
export const apiClient: ApiClient = new ApiWebClient()