API requests
Orderly provides both public and private APIs. Public APIs can be visited directly. Private APIs requires authentication and signatures, and these can be performed using hooks from @orderly.network/hooks
.
Reminder: Normally you would not have to use the following hooks, as
@orderly.network/hooks
already implements higher level hooks on top of the
request module. For example, you can use
usePositionStream
for position management, and
useOrderEntry
for
order placement. You may consider to use these hooks if you want to build out
more advanced usage of Orderly, or if the provided hooks are not suitable for
your use case.
RESTful API
@orderly.network/hooks
provides the following hooks for builders to access Orderly's RESTful APIs:
The above hooks are based on swr (opens in a new tab), and have the following properties:
- Request responses are cached. Cached data are used in priority according to the config, and is used as a global status management.
- Removes any duplicate requests. When request parameters are the same, it will automatically cancel the duplicate request
- When the window is focused or when the connection is recovered, automatically retries requests.
- Automatically retries any failed network requests.
- For more information, please check the official swr documentation (opens in a new tab).
Public APIs
Use useQuery
to access any Public API, for example to get all available symbols on Orderly:
() => { const { data, error, loading } = useQuery<API.Symbol[]>("/v1/public/info"); return ( <pre className="text-sm"> {loading && <div>Loading...</div>} {data && ( <div className="text-slate-500">{JSON.stringify(data, null, 2)}</div> )} </pre> ); };
The data
returned by useQuery
is already serialized in JSON format. If you want to access the raw data, you can provide a formatter
to override the default serialization of the hook. For example:
import { useQuery } from "@orderly.network/hooks";
const { data, error } = useQuery("/v1/public/info", {
formatter: (data) => data,
});
Private APIs
Use usePrivateQuery
, usePrivateInfiniteQuery
or useMutation
to access any Private API. These are slightly different from useQuery
:
- These have a built-in account status check. Builders do not have to check the current login status of the user. If the user has not logged in, the request will not be sent until the user status has changed to a logged in status.
- These will automatically sign all requests using the
OrderlyKey
according to Orderly's standards.
Use usePrivateQuery
to access a private API, for example to get the current user info:
const {usePrivateQuery} from "@orderly.network/hooks";
export const Example = ()=>{
const {data,loading,error} = usePrivateQuery<API.AccountInfo>("/v1/client/info");
//...
}
() => { const { data, loading, error } = usePrivateQuery("/v1/client/info"); if (loading) return <div>loading...</div>; return ( <div> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); };
Mutation
Note: useQuery
/usePrivateQuery
can only be used for GET
requests.
For POST
, PUT
or DELETE
requests, please use useMutation
. For example to create a new order:
import { useMutation } from "@orderly.network/hooks";
const [createOrder, { data, error, isMutating }] = useMutation<
OrderEntity,
any
>("/v1/order");
Infinite scrolling
Position list or order lists typically requires pagination to load all the data. If an infinite scrolling effect has to be implemented, usePrivateInfiniteQuery
can be used to help builders.
Slightly different from sending a incremental page
parameter, usePrivateInfiniteQuery
will append data from the next page
to data
, and not replacing the current response.
For example, to get the list of orders:
const { data: orders } = usePrivateInfiniteQuery(
(pageIndex: number, previousPageData) => {
// reached the end
if (previousPageData && !previousPageData.length) return null;
const search = new URLSearchParams([
["size", size.toString()],
["page", `${pageIndex + 1}`],
]);
// order status
if (status) {
search.set(`status`, status);
}
if (symbol) {
search.set(`symbol`, symbol);
}
if (side) {
search.set(`side`, side);
}
return `/v1/orders?${search.toString()}`;
},
{
initialSize: 1,
onError: (err) => {
console.error("fetch failed::::", err);
},
}
);
Why are we creating different hooks for different http methods, instead of
determining GET
vs POST
through a parameter?
Single responsibility principle: A function should only be responisble for one thing.
Reduces the complexity of the code, and prevents uncertainty from any side effects of the implementation.
WebSocket
@orderly.network/hooks
provides a useWS
hook for accessing Orderly's Websocket API. useWS
returns the WS
instance of @orderly.network/net
. Builders can use WS
to subscribe, cancel, or to send messages through the websocket. For more information, please see WS
For all available topics of the websocket, please check the websocket API documentation.
Subscribing to public topics
subscribe(
topic: string|{[key:string]:any},
callback: WSMessageHandler | Omit<WSMessageHandler, "onUnsubscribe">,
once?: boolean,
id?: string
): unsubscribe | undefined
Subscribing to the trade
topic:
import { useEffect } from "react";
import { useWS } from "@orderly.network/hooks";
export const Example = () => {
const ws = useWS();
useEffect(() => {
const unsubscript = ws.subscribe(
{
id: `${symbol}@trade`,
event: "subscribe",
topic: `${symbol}@trade`,
ts: Date.now(),
},
{
onMessage: (data: any) => {
//
},
}
);
() => {
// Unsubscribes when the component unloads
unsubscribe();
};
}, []);
//...
};
Subscribing to private topics
subscribe(
topic: string|{[key:string]:any},
callback: WSMessageHandler | Omit<WSMessageHandler, "onUnsubscribe">,
once?: boolean,
id?: string
): unsubscribe | undefined
Subscribing to the executionreport
topic:
import { useWS } from "@orderly.network/hooks";
export const Example = () => {
const ws = useWS();
useEffect(() => {
const unsubscript = ws.privateSubscribe(
{
id: "executionreport",
event: "subscribe",
topic: "executionreport",
ts: Date.now(),
},
{
onMessage: (data) => {
// do something
},
}
);
() => {
// Unsubscribes when the component unloads
unsubscribe();
};
}, []);
//...
};