Skip to content

Commit a7bc472

Browse files
authored
refactor(core): improve HTTP API, closes #1098 (#1237)
1 parent e34ee4c commit a7bc472

File tree

16 files changed

+1540
-487
lines changed

16 files changed

+1540
-487
lines changed

.changes/http-api-refactor.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"api": minor
3+
"tauri-api": minor
4+
"tauri": minor
5+
---
6+
7+
The HTTP API was improved with client caching and better payload and response types.

api/src/http.ts

Lines changed: 188 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,43 @@
1-
import { promisified } from './tauri'
1+
import { invoke, promisified } from './tauri'
2+
3+
export interface ClientOptions {
4+
maxRedirections: boolean
5+
connectTimeout: number
6+
}
27

38
export enum ResponseType {
49
JSON = 1,
510
Text = 2,
611
Binary = 3
712
}
813

9-
export enum BodyType {
10-
Form = 1,
11-
File = 2,
12-
Auto = 3
13-
}
14+
export type Part = 'string' | number[]
15+
16+
export class Body {
17+
type: string
18+
payload: unknown
1419

15-
export type Body = object | string | BinaryType
20+
constructor(type: string, payload: unknown) {
21+
this.type = type
22+
this.payload = payload
23+
}
24+
25+
static form(data: Record<string, Part>): Body {
26+
return new Body('Form', data)
27+
}
28+
29+
static json(data: Record<any, any>): Body {
30+
return new Body('Json', data)
31+
}
32+
33+
static text(value: string): Body {
34+
return new Body('Text', value)
35+
}
36+
37+
static bytes(bytes: number[]): Body {
38+
return new Body('Bytes', bytes)
39+
}
40+
}
1641

1742
export type HttpVerb =
1843
| 'GET'
@@ -29,130 +54,176 @@ export interface HttpOptions {
2954
method: HttpVerb
3055
url: string
3156
headers?: Record<string, any>
32-
params?: Record<string, any>
57+
query?: Record<string, any>
3358
body?: Body
34-
followRedirects: boolean
35-
maxRedirections: boolean
36-
connectTimeout: number
37-
readTimeout: number
38-
timeout: number
39-
allowCompression: boolean
59+
timeout?: number
4060
responseType?: ResponseType
41-
bodyType: BodyType
4261
}
4362

44-
export type PartialOptions = Omit<HttpOptions, 'method' | 'url'>
45-
46-
/**
47-
* makes a HTTP request
48-
*
49-
* @param options request options
50-
*
51-
* @return promise resolving to the response
52-
*/
53-
async function request<T>(options: HttpOptions): Promise<T> {
54-
return await promisified({
55-
module: 'Http',
56-
message: {
57-
cmd: 'httpRequest',
58-
options: options
59-
}
60-
})
61-
}
63+
export type RequestOptions = Omit<HttpOptions, 'method' | 'url'>
64+
export type FetchOptions = Omit<HttpOptions, 'url'>
6265

63-
/**
64-
* makes a GET request
65-
*
66-
* @param url request URL
67-
* @param options request options
68-
*
69-
* @return promise resolving to the response
70-
*/
71-
async function get<T>(url: string, options: PartialOptions): Promise<T> {
72-
return await request({
73-
method: 'GET',
74-
url,
75-
...options
76-
})
66+
export interface Response<T> {
67+
url: string
68+
status: number
69+
headers: Record<string, string>
70+
data: T
7771
}
7872

79-
/**
80-
* makes a POST request
81-
*
82-
* @param url request URL
83-
* @param body request body
84-
* @param options request options
85-
*
86-
* @return promise resolving to the response
87-
*/
88-
async function post<T>(
89-
url: string,
90-
body: Body,
91-
options: PartialOptions
92-
): Promise<T> {
93-
return await request({
94-
method: 'POST',
95-
url,
96-
body,
97-
...options
98-
})
99-
}
73+
export class Client {
74+
id: number
75+
constructor(id: number) {
76+
this.id = id
77+
}
10078

101-
/**
102-
* makes a PUT request
103-
*
104-
* @param url request URL
105-
* @param body request body
106-
* @param options request options
107-
*
108-
* @return promise resolving to the response
109-
*/
110-
async function put<T>(
111-
url: string,
112-
body: Body,
113-
options: PartialOptions
114-
): Promise<T> {
115-
return await request({
116-
method: 'PUT',
117-
url,
118-
body,
119-
...options
120-
})
79+
/**
80+
* drops the client instance
81+
*/
82+
drop(): void {
83+
invoke({
84+
module: 'Http',
85+
message: {
86+
cmd: 'dropClient',
87+
client: this.id
88+
}
89+
})
90+
}
91+
92+
/**
93+
* makes a HTTP request
94+
*
95+
* @param options request options
96+
*
97+
* @return promise resolving to the response
98+
*/
99+
async request<T>(options: HttpOptions): Promise<Response<T>> {
100+
return await promisified({
101+
module: 'Http',
102+
message: {
103+
cmd: 'httpRequest',
104+
client: this.id,
105+
options
106+
}
107+
})
108+
}
109+
110+
/**
111+
* makes a GET request
112+
*
113+
* @param url request URL
114+
* @param options request options
115+
*
116+
* @return promise resolving to the response
117+
*/
118+
async get<T>(url: string, options: RequestOptions): Promise<Response<T>> {
119+
return await this.request({
120+
method: 'GET',
121+
url,
122+
...options
123+
})
124+
}
125+
126+
/**
127+
* makes a POST request
128+
*
129+
* @param url request URL
130+
* @param body request body
131+
* @param options request options
132+
*
133+
* @return promise resolving to the response
134+
*/
135+
async post<T>(
136+
url: string,
137+
body: Body,
138+
options: RequestOptions
139+
): Promise<Response<T>> {
140+
return await this.request({
141+
method: 'POST',
142+
url,
143+
body,
144+
...options
145+
})
146+
}
147+
148+
/**
149+
* makes a PUT request
150+
*
151+
* @param url request URL
152+
* @param body request body
153+
* @param options request options
154+
*
155+
* @return promise resolving to the response
156+
*/
157+
async put<T>(
158+
url: string,
159+
body: Body,
160+
options: RequestOptions
161+
): Promise<Response<T>> {
162+
return await this.request({
163+
method: 'PUT',
164+
url,
165+
body,
166+
...options
167+
})
168+
}
169+
170+
/**
171+
* makes a PATCH request
172+
*
173+
* @param url request URL
174+
* @param options request options
175+
*
176+
* @return promise resolving to the response
177+
*/
178+
async patch<T>(url: string, options: RequestOptions): Promise<Response<T>> {
179+
return await this.request({
180+
method: 'PATCH',
181+
url,
182+
...options
183+
})
184+
}
185+
186+
/**
187+
* makes a DELETE request
188+
*
189+
* @param url request URL
190+
* @param options request options
191+
*
192+
* @return promise resolving to the response
193+
*/
194+
async delete<T>(
195+
url: string,
196+
options: RequestOptions
197+
): Promise<Response<T>> {
198+
return await this.request({
199+
method: 'DELETE',
200+
url,
201+
...options
202+
})
203+
}
121204
}
122205

123-
/**
124-
* makes a PATCH request
125-
*
126-
* @param url request URL
127-
* @param options request options
128-
*
129-
* @return promise resolving to the response
130-
*/
131-
async function patch<T>(url: string, options: PartialOptions): Promise<T> {
132-
return await request({
133-
method: 'PATCH',
134-
url,
135-
...options
136-
})
206+
async function getClient(options?: ClientOptions): Promise<Client> {
207+
return await promisified<number>({
208+
module: 'Http',
209+
message: {
210+
cmd: 'createClient',
211+
options
212+
}
213+
}).then(id => new Client(id))
137214
}
138215

139-
/**
140-
* makes a DELETE request
141-
*
142-
* @param url request URL
143-
* @param options request options
144-
*
145-
* @return promise resolving to the response
146-
*/
147-
async function deleteRequest<T>(
148-
url: string,
149-
options: PartialOptions
150-
): Promise<T> {
151-
return await request({
152-
method: 'DELETE',
216+
let defaultClient: Client | null = null
217+
218+
async function fetch<T>(url: string, options?: FetchOptions): Promise<Response<T>> {
219+
if (defaultClient === null) {
220+
defaultClient = await getClient()
221+
}
222+
return await defaultClient.request({
153223
url,
224+
method: options?.method ?? 'GET',
154225
...options
155226
})
156227
}
157228

158-
export { request, get, post, put, patch, deleteRequest as httpDelete }
229+
export { getClient, fetch }

tauri-api/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ thiserror = "1.0.23"
2929
rand = "0.8"
3030
nfd = "0.0.4"
3131
tauri-dialog = "0.1.0"
32-
attohttpc = { version = "0.16.1", features = [ "json", "form" ] }
32+
reqwest = { version = "0.11", features = [ "json", "multipart" ] }
33+
bytes = { version = "1", features = ["serde"] }
3334
http = "0.2"
3435
tauri-utils = { version = "0.5", path = "../tauri-utils" }
3536
clap = { version = "=3.0.0-beta.2", optional = true }

0 commit comments

Comments
 (0)