Skip to content

Commit e090418

Browse files
Add support for send file upload api
1 parent b7ea9f0 commit e090418

File tree

10 files changed

+206
-0
lines changed

10 files changed

+206
-0
lines changed

Src/Notion.Client/Api/ApiEndpoints.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ public static class AuthenticationUrls
143143
public static class FileUploadsApiUrls
144144
{
145145
public static string Create() => "/v1/file_uploads";
146+
public static string Send(string fileUploadId) => $"/v1/file_uploads/{fileUploadId}/send";
146147
}
147148
}
148149
}

Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,19 @@ Task<CreateFileUploadResponse> CreateAsync(
1515
CreateFileUploadRequest fileUploadObjectRequest,
1616
CancellationToken cancellationToken = default
1717
);
18+
19+
/// <summary>
20+
/// Send a file upload
21+
///
22+
/// Requires a `file_upload_id`, obtained from the `id` of the Create File Upload API response.
23+
///
24+
/// </summary>
25+
/// <param name="sendFileUploadRequest"></param>
26+
/// <param name="cancellationToken"></param>
27+
/// <returns></returns>
28+
Task<SendFileUploadResponse> SendAsync(
29+
SendFileUploadRequest sendFileUploadRequest,
30+
CancellationToken cancellationToken = default
31+
);
1832
}
1933
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Notion.Client
6+
{
7+
public sealed partial class FileUploadsClient
8+
{
9+
public async Task<SendFileUploadResponse> SendAsync(
10+
SendFileUploadRequest sendFileUploadRequest,
11+
CancellationToken cancellationToken = default)
12+
{
13+
if (sendFileUploadRequest == null)
14+
{
15+
throw new ArgumentNullException(nameof(sendFileUploadRequest));
16+
}
17+
18+
if (string.IsNullOrEmpty(sendFileUploadRequest.FileUploadId))
19+
{
20+
throw new ArgumentNullException(nameof(sendFileUploadRequest.FileUploadId));
21+
}
22+
23+
var path = ApiEndpoints.FileUploadsApiUrls.Send(sendFileUploadRequest.FileUploadId);
24+
25+
return await _restClient.PostAsync<SendFileUploadResponse>(
26+
path,
27+
formData: sendFileUploadRequest,
28+
cancellationToken: cancellationToken
29+
);
30+
}
31+
}
32+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.IO;
2+
using Newtonsoft.Json;
3+
4+
namespace Notion.Client
5+
{
6+
public class SendFileUploadRequest : ISendFileUploadFormDataParameters, ISendFileUploadPathParameters
7+
{
8+
public FileData File { get; private set; }
9+
public string PartNumber { get; private set; }
10+
public string FileUploadId { get; private set; }
11+
12+
private SendFileUploadRequest() { }
13+
14+
public static SendFileUploadRequest Create(string fileUploadId, FileData file, string partNumber = null)
15+
{
16+
return new SendFileUploadRequest
17+
{
18+
FileUploadId = fileUploadId,
19+
File = file,
20+
PartNumber = partNumber
21+
};
22+
}
23+
}
24+
25+
public interface ISendFileUploadFormDataParameters
26+
{
27+
28+
/// <summary>
29+
/// The raw binary file contents to upload.
30+
/// </summary>
31+
FileData File { get; }
32+
33+
/// <summary>
34+
/// When using a mode=multi_part File Upload to send files greater than 20 MB in parts, this is the current part number.
35+
/// Must be an integer between 1 and 1000 provided as a string form field.
36+
/// </summary>
37+
[JsonProperty("part_number")]
38+
string PartNumber { get; }
39+
}
40+
41+
public class FileData
42+
{
43+
/// <summary>
44+
/// The name of the file being uploaded.
45+
/// </summary>
46+
public string FileName { get; set; }
47+
48+
/// <summary>
49+
/// The content of the file being uploaded.
50+
/// </summary>
51+
public Stream Data { get; set; }
52+
53+
/// <summary>
54+
/// The MIME type of the file being uploaded.
55+
/// </summary>
56+
public string ContentType { get; set; }
57+
}
58+
59+
public interface ISendFileUploadPathParameters
60+
{
61+
/// <summary>
62+
/// The `file_upload_id` obtained from the `id` of the Create File Upload API response.
63+
/// </summary>
64+
string FileUploadId { get; }
65+
}
66+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Notion.Client
2+
{
3+
public class SendFileUploadResponse : FileObjectResponse
4+
{
5+
}
6+
}

Src/Notion.Client/RestClient/IRestClient.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ Task<T> PostAsync<T>(
2323
IBasicAuthenticationParameters basicAuthenticationParameters = null,
2424
CancellationToken cancellationToken = default);
2525

26+
Task<T> PostAsync<T>(
27+
string uri,
28+
ISendFileUploadFormDataParameters formData,
29+
IEnumerable<KeyValuePair<string, string>> queryParams = null,
30+
IDictionary<string, string> headers = null,
31+
JsonSerializerSettings serializerSettings = null,
32+
IBasicAuthenticationParameters basicAuthenticationParameters = null,
33+
CancellationToken cancellationToken = default);
34+
2635
Task<T> PatchAsync<T>(
2736
string uri,
2837
object body,

Src/Notion.Client/RestClient/RestClient.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,46 @@ void AttachContent(HttpRequestMessage httpRequest)
7070
return await response.ParseStreamAsync<T>(serializerSettings);
7171
}
7272

73+
public async Task<T> PostAsync<T>(
74+
string uri,
75+
ISendFileUploadFormDataParameters formData,
76+
IEnumerable<KeyValuePair<string, string>> queryParams = null,
77+
IDictionary<string, string> headers = null,
78+
JsonSerializerSettings serializerSettings = null,
79+
IBasicAuthenticationParameters basicAuthenticationParameters = null,
80+
CancellationToken cancellationToken = default)
81+
{
82+
void AttachContent(HttpRequestMessage httpRequest)
83+
{
84+
var fileContent = new StreamContent(formData.File.Data);
85+
fileContent.Headers.ContentType = new MediaTypeHeaderValue(formData.File.ContentType);
86+
87+
var form = new MultipartFormDataContent
88+
{
89+
{ fileContent, "file", formData.File.FileName }
90+
};
91+
92+
if (!string.IsNullOrEmpty(formData.PartNumber))
93+
{
94+
form.Add(new StringContent(formData.PartNumber), "part_number");
95+
}
96+
97+
httpRequest.Content = form;
98+
}
99+
100+
var response = await SendAsync(
101+
uri,
102+
HttpMethod.Post,
103+
queryParams,
104+
headers,
105+
AttachContent,
106+
basicAuthenticationParameters,
107+
cancellationToken
108+
);
109+
110+
return await response.ParseStreamAsync<T>(serializerSettings);
111+
}
112+
73113
public async Task<T> PatchAsync<T>(
74114
string uri,
75115
object body,

Test/Notion.IntegrationTests/FIleUploadsClientTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,37 @@ public async Task CreateAsync()
2525
Assert.NotNull(response.Status);
2626
Assert.Equal("sample-image.jpg", response.FileName);
2727
}
28+
29+
[Fact]
30+
public async Task Verify_file_upload_flow()
31+
{
32+
// Arrange
33+
var createRequest = new CreateFileUploadRequest
34+
{
35+
Mode = FileUploadMode.SinglePart,
36+
Filename = "notion-logo.png",
37+
};
38+
39+
var createResponse = await Client.FileUploads.CreateAsync(createRequest);
40+
41+
var sendRequest = SendFileUploadRequest.Create(
42+
createResponse.Id,
43+
new FileData
44+
{
45+
FileName = "notion-logo.png",
46+
Data = System.IO.File.OpenRead("assets/notion-logo.png"),
47+
ContentType = createResponse.ContentType
48+
}
49+
);
50+
51+
// Act
52+
var sendResponse = await Client.FileUploads.SendAsync(sendRequest);
53+
54+
// Assert
55+
Assert.NotNull(sendResponse);
56+
Assert.Equal(createResponse.Id, sendResponse.Id);
57+
Assert.Equal("notion-logo.png", sendResponse.FileName);
58+
Assert.Equal("uploaded", sendResponse.Status);
59+
}
2860
}
2961
}

Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
<ProjectReference Include="..\..\Src\Notion.Client\Notion.Client.csproj" />
1212
</ItemGroup>
1313

14+
<ItemGroup>
15+
<Content Include="assets\notion-logo.png">
16+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
17+
</Content>
18+
</ItemGroup>
19+
1420
<ItemGroup>
1521
<PackageReference Include="FluentAssertions" Version="5.10.3" />
1622
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
9.12 KB
Loading

0 commit comments

Comments
 (0)