Skip to content

Commit 2d13c27

Browse files
Lustmoredweaverryan
authored andcommitted
Allow files to be passed to RequestBuilder and move request body under 'data' key
1 parent 21d16ea commit 2d13c27

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

src/LiveComponent/assets/src/Backend/Backend.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ export default class implements BackendInterface {
3434
updated: {[key: string]: any},
3535
children: ChildrenFingerprints,
3636
updatedPropsFromParent: {[key: string]: any},
37+
files: {[key: string]: FileList} = {},
3738
): BackendRequest {
3839
const { url, fetchOptions } = this.requestBuilder.buildRequest(
3940
props,
4041
actions,
4142
updated,
4243
children,
43-
updatedPropsFromParent
44+
updatedPropsFromParent,
45+
files
4446
);
4547

4648
return new BackendRequest(

src/LiveComponent/assets/src/Backend/RequestBuilder.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default class {
1515
updated: {[key: string]: any},
1616
children: ChildrenFingerprints,
1717
updatedPropsFromParent: {[key: string]: any},
18+
files: {[key: string]: FileList},
1819
): { url: string; fetchOptions: RequestInit } {
1920
const splitUrl = this.url.split('?');
2021
let [url] = splitUrl;
@@ -42,7 +43,6 @@ export default class {
4243
fetchOptions.method = 'GET';
4344
} else {
4445
fetchOptions.method = 'POST';
45-
fetchOptions.headers['Content-Type'] = 'application/json';
4646
const requestData: any = { props, updated };
4747
if (Object.keys(updatedPropsFromParent).length > 0) {
4848
requestData.propsFromParent = updatedPropsFromParent;
@@ -68,7 +68,17 @@ export default class {
6868
}
6969
}
7070

71-
fetchOptions.body = JSON.stringify(requestData);
71+
const formData = new FormData();
72+
formData.append('data', JSON.stringify(requestData));
73+
74+
for(const [key, value] of Object.entries(files)) {
75+
const length = value.length;
76+
for (let i = 0; i < length ; ++i) {
77+
formData.append(key, value[i]);
78+
}
79+
}
80+
81+
fetchOptions.body = formData;
7282
}
7383

7484
const paramsString = params.toString();

src/LiveComponent/assets/test/Backend/RequestBuilder.test.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ describe('buildRequest', () => {
88
[],
99
{ firstName: 'Kevin' },
1010
{ 'child-component': {fingerprint: '123', tag: 'div' } },
11+
{},
1112
{}
1213
);
1314

@@ -28,17 +29,20 @@ describe('buildRequest', () => {
2829
}],
2930
{ firstName: 'Kevin' },
3031
{ 'child-component': {fingerprint: '123', tag: 'div' } },
32+
{},
3133
{}
3234
);
3335

3436
expect(url).toEqual('/_components/saveData');
3537
expect(fetchOptions.method).toEqual('POST');
3638
expect(fetchOptions.headers).toEqual({
3739
Accept: 'application/vnd.live-component+html',
38-
'Content-Type': 'application/json',
3940
'X-CSRF-TOKEN': '_the_csrf_token',
4041
});
41-
expect(fetchOptions.body).toEqual(JSON.stringify({
42+
const body = fetchOptions.body;
43+
expect(body).toBeInstanceOf(FormData);
44+
// @ts-ignore body is already asserted to be FormData
45+
expect(body.get('data')).toEqual(JSON.stringify({
4246
props: { firstName: 'Ryan' },
4347
updated: { firstName: 'Kevin' },
4448
children: { 'child-component': { fingerprint: '123', tag: 'div' } },
@@ -59,12 +63,16 @@ describe('buildRequest', () => {
5963
}],
6064
{ firstName: 'Kevin' },
6165
{},
66+
{},
6267
{}
6368
);
6469

6570
expect(url).toEqual('/_components/_batch');
6671
expect(fetchOptions.method).toEqual('POST');
67-
expect(fetchOptions.body).toEqual(JSON.stringify({
72+
const body = fetchOptions.body;
73+
expect(body).toBeInstanceOf(FormData);
74+
// @ts-ignore body is already asserted to be FormData
75+
expect(body.get('data')).toEqual(JSON.stringify({
6876
props: { firstName: 'Ryan' },
6977
updated: { firstName: 'Kevin' },
7078
actions: [{
@@ -85,6 +93,7 @@ describe('buildRequest', () => {
8593
[],
8694
{ firstName: 'Kevin'.repeat(1000) },
8795
{},
96+
{},
8897
{}
8998
);
9099

@@ -93,9 +102,11 @@ describe('buildRequest', () => {
93102
expect(fetchOptions.headers).toEqual({
94103
// no token
95104
Accept: 'application/vnd.live-component+html',
96-
'Content-Type': 'application/json',
97105
});
98-
expect(fetchOptions.body).toEqual(JSON.stringify({
106+
const body = fetchOptions.body;
107+
expect(body).toBeInstanceOf(FormData);
108+
// @ts-ignore body is already asserted to be FormData
109+
expect(body.get('data')).toEqual(JSON.stringify({
99110
props: { firstName: 'Ryan'.repeat(1000) },
100111
updated: { firstName: 'Kevin'.repeat(1000) },
101112
}));
@@ -108,7 +119,8 @@ describe('buildRequest', () => {
108119
[],
109120
{ firstName: 'Kevin' },
110121
{ },
111-
{ count: 5 }
122+
{ count: 5 },
123+
{}
112124
);
113125

114126
expect(url).toEqual('/_components?existing_param=1&props=%7B%22firstName%22%3A%22Ryan%22%7D&updated=%7B%22firstName%22%3A%22Kevin%22%7D&propsFromParent=%7B%22count%22%3A5%7D');
@@ -123,9 +135,13 @@ describe('buildRequest', () => {
123135
{ firstName: 'Kevin' },
124136
{},
125137
{ count: 5 },
138+
{}
126139
);
127140

128-
expect(fetchOptions.body).toEqual(JSON.stringify({
141+
const body = fetchOptions.body;
142+
expect(body).toBeInstanceOf(FormData);
143+
// @ts-ignore body is already asserted to be FormData
144+
expect(body.get('data')).toEqual(JSON.stringify({
129145
props: { firstName: 'Ryan' },
130146
updated: { firstName: 'Kevin' },
131147
propsFromParent: { count: 5 },

0 commit comments

Comments
 (0)