Skip to content

Commit 780a673

Browse files
committed
Update Add ServiceStack reference examples
1 parent e58cc4a commit 780a673

10 files changed

+549
-114
lines changed

MyApp/_pages/add-servicestack-reference.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ The [x dotnet tool](/dotnet-tool) provides simple command-line utilities to easi
140140
dotnet tool install --global x
141141
:::
142142

143+
::include npx-get-dtos.md::
144+
143145
This will make the following utilities available from your command-line which will let you download the Server DTO classes for a remote ServiceStack endpoint in your chosen language which you can use with ServiceStack's generic Service clients to be able to make end-to-end API calls.
144146

145147
<table class="table table-bordered">
@@ -390,6 +392,119 @@ in the right-click context menu:
390392

391393
If you're updating references frequently you can save time by [assigning it a keyboard shortcut](https://www.jetbrains.com/help/rider/Configuring_Keyboard_and_Mouse_Shortcuts.html).
392394

395+
396+
## Multiple File Upload Support with API Requests supported in all languages
397+
398+
To be able to call [AI Server](/ai-server/) APIs requiring file uploads we've added multiple file upload support with API Requests to the generic service clients for all our supported languages.
399+
400+
Here's what that looks like for different languages calling AI Server's `SpeechToText` API:
401+
402+
### C# Speech to Text
403+
404+
```csharp
405+
using var fsAudio = File.OpenRead("audio.wav");
406+
var response = client.PostFileWithRequest(new SpeechToText(),
407+
new UploadFile("audio.wav", fsAudio, "audio"));
408+
```
409+
410+
### Dart Speech to Text
411+
412+
```dart
413+
var audioFile = new File('audio.wav');
414+
var uploadFile = new UploadFile(
415+
fieldName: 'audio',
416+
fileName: audioFile.uri.pathSegments.last,
417+
contentType: 'audio/wav',
418+
contents: await audioFile.readAsBytes()
419+
);
420+
421+
var response = await client.postFileWithRequest(new SpeechToText(), uploadFile);
422+
```
423+
424+
### Python Speech to Text
425+
426+
```python
427+
with open("files/audio.wav", "rb") as audio:
428+
response = client.post_file_with_request(SpeechToText(),
429+
UploadFile(field_name="audio", file_name="audio.wav", content_type="audio/wav", stream=audio))
430+
```
431+
432+
### PHP Speech to Text
433+
434+
```php
435+
$audioFile = __DIR__ . '/files/audio.wav';
436+
437+
/** @var GenerationResponse $response */
438+
$response = $client->postFileWithRequest(new SpeechToText(),
439+
new UploadFile(
440+
filePath: $audioFile,
441+
fileName: 'audio.wav',
442+
fieldName: 'audio',
443+
contentType: 'audio/wav'
444+
));
445+
```
446+
447+
### Swift Speech to Text
448+
449+
```swift
450+
guard let audioURL = Bundle.module.url(forResource: "audio.wav", withExtension: nil) else {
451+
return
452+
}
453+
454+
let audioData = try Data(contentsOf: audioURL)
455+
let response: TextGenerationResponse = try await client.postFileWithRequestAsync(
456+
request:SpeechToText(),
457+
file:UploadFile(fileName: "audio.wav", data:audioData, fieldName:"audio"))
458+
```
459+
460+
### Kotlin Speech to Text
461+
462+
```kotlin
463+
val audioBytes = Files.readAllBytes(Paths.get("audio.wav"))
464+
val response = client.postFileWithRequest(SpeechToText(),
465+
UploadFile("audio", "audio.wav", "audio/wav", audioBytes))
466+
```
467+
468+
### Java Speech to Text
469+
470+
```java
471+
byte[] audioBytes = Files.readAllBytes(Paths.get("audio.wav"));
472+
var response = client.postFileWithRequest(request,
473+
new UploadFile("audio", "audio.wav", "audio/wav", audioBytes));
474+
```
475+
476+
### TypeScript Speech to Text
477+
478+
```js
479+
// Create FormData and append the file
480+
const formData = new FormData()
481+
const audioFile = fs.readFileSync('audio.wav')
482+
const blob = new Blob([audioFile], { type: 'audio/wav' })
483+
484+
// Explicitly set the field name as 'audio'
485+
formData.append('audio', blob, 'audio.wav')
486+
487+
const api = await client.apiForm(new SpeechToText(), formData)
488+
```
489+
490+
### Multiple File Uploads
491+
492+
All languages also support a `postFilesWithRequest` variant for uploading multiple files with an API Request.
493+
E.g. here's an example of using `PostFilesWithRequest` to generate a video with a Watermark:
494+
495+
### C# Watermark Video
496+
497+
```csharp
498+
using var fsVideo = File.OpenRead("video.mp4");
499+
using var fsWatermark = File.OpenRead("watermark.png");
500+
var response = client.PostFilesWithRequest(new QueueWatermarkVideo {
501+
Position = WatermarkPosition.BottomRight
502+
}, [
503+
new UploadFile("video.mp4", fsVideo, "video"),
504+
new UploadFile("watermark.png", fsWatermark, "watermark")
505+
]);
506+
```
507+
393508
## Advantages over WCF
394509

395510
- **Simple** Server provides DTOs based on metadata and options provided. No heavy client side tools, just a HTTP request!

MyApp/_pages/csharp-client.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,38 @@ var response = await client.SendAsync<HelloResponse>(
184184

185185
The service clients use the automatic [pre-defined routes](/endpoints) for each service.
186186

187+
### File Upload with Request
188+
189+
The `PostFileWithRequest*` methods can be used to upload a file with an API Request.
190+
191+
Here's an example calling [AI Server's](/ai-server/) `SpeechToText` API:
192+
193+
### C# Speech to Text
194+
195+
```csharp
196+
using var fsAudio = File.OpenRead("audio.wav");
197+
var response = client.PostFileWithRequest(new SpeechToText(),
198+
new UploadFile("audio.wav", fsAudio, "audio"));
199+
```
200+
201+
### Multiple File Uploads
202+
203+
Whilst the `PostFilesWithRequest*` methods can be used to upload multiple files with an API Request, e.g:
204+
205+
### C# Watermark Video
206+
207+
```csharp
208+
using var fsVideo = File.OpenRead("video.mp4");
209+
using var fsWatermark = File.OpenRead("watermark.png");
210+
var response = client.PostFilesWithRequest(new QueueWatermarkVideo {
211+
Position = WatermarkPosition.BottomRight
212+
}, [
213+
new UploadFile("video.mp4", fsVideo, "video"),
214+
new UploadFile("watermark.png", fsWatermark, "watermark")
215+
]);
216+
```
217+
218+
187219
<a name="native-responses"></a>
188220

189221
### [Cache Aware Service Clients](/cache-aware-clients)

MyApp/_pages/dart-add-servicestack-reference.md

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -262,36 +262,62 @@ Both JSON Service Client variants implement the same flexible `IServiceClient` A
262262

263263
```csharp
264264
abstract class IServiceClient {
265-
String baseUrl;
266-
String bearerToken;
267-
String refreshToken;
268-
String userName;
269-
String password;
265+
String? baseUrl;
266+
String? replyBaseUrl;
267+
String? oneWayBaseUrl;
270268
271-
Future<T> get<T>(IReturn<T> request, {Map<String, dynamic> args});
272-
Future<Map<String, dynamic>> getUrl(String path, {Map<String, dynamic> args});
273-
Future<T> getAs<T>(String path, {Map<String, dynamic> args, T responseAs});
269+
String? bearerToken;
270+
String? refreshToken;
271+
String? userName;
272+
String? password;
274273
275-
Future<T> post<T>(IReturn<T> request, {dynamic body, Map<String, dynamic> args});
276-
Future<Map<String, dynamic>> postToUrl(String path, dynamic body, {Map<String, dynamic> args});
277-
Future<T> postAs<T>(String path, dynamic body, {Map<String, dynamic> args, T responseAs});
274+
AsyncCallbackFunction? onAuthenticationRequired;
275+
String? getTokenCookie();
276+
String? getRefreshTokenCookie();
278277
279-
Future<T> delete<T>(IReturn<T> request, {Map<String, dynamic> args});
280-
Future<Map<String, dynamic>> deleteUrl(String path, {Map<String, dynamic> args});
281-
Future<T> deleteAs<T>(String path, {Map<String, dynamic> args, T responseAs});
278+
void clearCookies();
282279
283-
Future<T> put<T>(IReturn<T> request, {dynamic body, Map<String, dynamic> args});
284-
Future<Map<String, dynamic>> putToUrl(String path, dynamic body, {Map<String, dynamic> args});
285-
Future<T> putAs<T>(String path, dynamic body, {Map<String, dynamic> args, T responseAs});
280+
Future<ApiResult<T>> api<T>(IReturn<T> request, {Map<String, dynamic>? args, String? method});
281+
282+
Future<ApiResult<EmptyResponse>> apiVoid(IReturnVoid request, {Map<String, dynamic>? args, String? method});
283+
284+
Future<T> get<T>(IReturn<T> request, {Map<String, dynamic>? args});
285+
286+
Future<Map<String, dynamic>> getUrl(String path, {Map<String, dynamic>? args});
287+
288+
Future<T> getAs<T>(String path, {Map<String, dynamic>? args, T? responseAs});
289+
290+
Future<T> post<T>(IReturn<T> request, {dynamic body, Map<String, dynamic>? args});
291+
292+
Future<Map<String, dynamic>> postToUrl(String path, dynamic body, {Map<String, dynamic>? args});
293+
294+
Future<T> postAs<T>(String path, dynamic body, {Map<String, dynamic>? args, T? responseAs});
295+
296+
Future<T> delete<T>(IReturn<T> request, {Map<String, dynamic>? args});
297+
298+
Future<Map<String, dynamic>> deleteUrl(String path, {Map<String, dynamic>? args});
299+
300+
Future<T> deleteAs<T>(String path, {Map<String, dynamic>? args, T? responseAs});
301+
302+
Future<T> put<T>(IReturn<T> request, {dynamic body, Map<String, dynamic>? args});
303+
304+
Future<Map<String, dynamic>> putToUrl(String path, dynamic body, {Map<String, dynamic>? args});
305+
306+
Future<T> putAs<T>(String path, dynamic body, {Map<String, dynamic>? args, T? responseAs});
307+
308+
Future<T> patch<T>(IReturn<T> request, {dynamic body, Map<String, dynamic>? args});
286309
287-
Future<T> patch<T>(IReturn<T> request, {dynamic body, Map<String, dynamic> args});
288310
Future<Map<String, dynamic>> patchToUrl(String path, dynamic body, {Map<String, dynamic> args});
289-
Future<T> patchAs<T>(String path, dynamic body, {Map<String, dynamic> args, T responseAs});
311+
312+
Future<T> patchAs<T>(String path, dynamic body, {Map<String, dynamic>? args, T? responseAs});
290313
291314
Future<List<T>> sendAll<T>(Iterable<IReturn<T>> requests);
315+
292316
Future<void> sendAllOneWay<T>(Iterable<IReturn<T>> requests);
293317
294-
Future<T> send<T>(IReturn<T> request, {String method, Map<String, dynamic> args, T responseAs});
318+
Future<T> send<T>(IReturn<T> request, {String? method, Map<String, dynamic>? args, T? responseAs});
319+
320+
void close({bool force = false});
295321
}
296322
```
297323

@@ -307,6 +333,29 @@ var webClient = JsonWebClient(baseUrl)
307333
..responseFilter = (res) => print(res.headers["X-Args"]);
308334
```
309335

336+
### Uploading Files
337+
338+
The `postFileWithRequest` method can be used to upload a file with an API Request.
339+
340+
### Dart Speech to Text
341+
342+
Here's an example calling [AI Server's](/ai-server/) `SpeechToText` API:
343+
344+
```dart
345+
var audioFile = new File('audio.wav');
346+
var uploadFile = new UploadFile(
347+
fieldName: 'audio',
348+
fileName: audioFile.uri.pathSegments.last,
349+
contentType: 'audio/wav',
350+
contents: await audioFile.readAsBytes()
351+
);
352+
353+
var response = await client.postFileWithRequest(new SpeechToText(), uploadFile);
354+
```
355+
356+
To upload multiple files use `postFilesWithRequest`.
357+
358+
310359
#### Comprehensive Test Suite
311360

312361
To ensure a high quality implementation we've ported the [TypeScript @servicestack/client](https://github.com/ServiceStack/servicestack-client) test suite over to Dart which is itself a good resource for discovering [different supported features and flexible HTTP Request options](https://github.com/ServiceStack/servicestack-dart/tree/master/test) available.

MyApp/_pages/java-add-servicestack-reference.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,15 @@ The [ServiceClient.java](https://github.com/ServiceStack/ServiceStack.Java/blob/
120120
```java
121121
public interface ServiceClient {
122122
boolean getAlwaysSendBasicAuthHeaders();
123+
124+
void setBearerToken(String value);
125+
String getBearerToken();
126+
void setTokenCookie(String value);
127+
128+
void setRefreshToken(String bearerToken);
129+
String getRefreshToken();
130+
void setRefreshTokenCookie(String value);
131+
123132
void setAlwaysSendBasicAuthHeaders(boolean value);
124133
void setCredentials(String userName, String password);
125134

@@ -155,6 +164,21 @@ public interface ServiceClient {
155164
<TResponse> TResponse delete(String path, Class responseType);
156165
<TResponse> TResponse delete(String path, Type responseType);
157166
HttpURLConnection delete(String path);
167+
168+
void setCookie(String name, String value);
169+
void setCookie(String name, String value, Long expiresInSecs);
170+
void clearCookies();
171+
String getCookieValue(String name);
172+
String getTokenCookie();
173+
String getRefreshTokenCookie();
174+
175+
<TResponse> TResponse postFileWithRequest(IReturn<TResponse> request, UploadFile file);
176+
<TResponse> TResponse postFileWithRequest(Object request, UploadFile file, Object responseType);
177+
<TResponse> TResponse postFileWithRequest(String path, Object request, UploadFile file, Object responseType);
178+
179+
<TResponse> TResponse postFilesWithRequest(IReturn<TResponse> request, UploadFile[] files);
180+
<TResponse> TResponse postFilesWithRequest(Object request, UploadFile[] files, Object responseType);
181+
<TResponse> TResponse postFilesWithRequest(String path, Object request, UploadFile[] files, Object responseType);
158182
}
159183
```
160184

@@ -261,6 +285,22 @@ AuthenticateResponse authResponse = client.post(new Authenticate()
261285
TestAuthResponse response = client.get(new TestAuth());
262286
```
263287

288+
### Uploading Files
289+
290+
The `postFileWithRequest` method can be used to upload a file with an API Request.
291+
292+
### Java Speech to Text
293+
294+
Here's an example calling [AI Server's](/ai-server/) `SpeechToText` API:
295+
296+
```java
297+
byte[] audioBytes = Files.readAllBytes(Paths.get("audio.wav"));
298+
var response = client.postFileWithRequest(request,
299+
new UploadFile("audio", "audio.wav", "audio/wav", audioBytes));
300+
```
301+
302+
To upload multiple files use `postFilesWithRequest`.
303+
264304
### AndroidServiceClient
265305
Unlike .NET, Java doesn't have an established Async story or any language support that simplifies execution and composition of Async tasks, as a result the Async story on Android is fairly fragmented with multiple options built-in for executing non-blocking tasks on different threads including:
266306

0 commit comments

Comments
 (0)