Serverpod Swagger Examples

This page provides practical examples of how to use Serverpod Swagger in different scenarios. Each example includes code snippets and explanations to help you implement Swagger UI in your Serverpod application.

Basic Example

This example shows the minimal setup required to add Swagger UI to your Serverpod server.

main.dart
1import 'dart:io';
2import 'package:serverpod/serverpod.dart';
3import 'package:serverpod_swagger/serverpod_swagger.dart';
4
5future<void> main() async {
6  // Create the server
7  final pod = Serverpod(
8    args,
9    [
10      // Your endpoint classes
11    ],
12  );
13  
14  // Add the Swagger UI route
15  pod.webServer.addRoute(
16    SwaggerUIRoute(
17      Directory(Directory.current.path),
18      mountPath: '/swagger/',
19    ),
20  );
21  
22  // Start the server
23  await pod.start();
24}

With this setup, you can access the Swagger UI at http://localhost:8082/swagger/ after generating the OpenAPI specification with dart run serverpod_swagger:generate.

Complete Example with Authentication

This example shows a more complete setup with authentication, custom styling, and multiple API versions.

Step 1: Create security definitions

openapi_security.yaml
1security:
2  - BearerAuth: []
3
4components:
5  securitySchemes:
6    BearerAuth:
7      type: http
8      scheme: bearer
9      bearerFormat: JWT
10      description: Enter your JWT token in the format 'Bearer {token}'

Step 2: Create custom CSS for Swagger UI

web/custom/swagger.css
1.swagger-ui .topbar {
2  background-color: #1a365d;
3}
4
5.swagger-ui .info .title {
6  color: #2c5282;
7}
8
9.swagger-ui .opblock-tag {
10  background-color: #ebf8ff;
11}
12
13.swagger-ui .opblock.opblock-get {
14  border-color: #4299e1;
15  background-color: #ebf8ff;
16}
17
18.swagger-ui .opblock.opblock-post {
19  border-color: #48bb78;
20  background-color: #f0fff4;
21}

Step 3: Configure the server with Swagger UI

main.dart
1import 'dart:io';
2import 'package:serverpod/serverpod.dart';
3import 'package:serverpod_swagger/serverpod_swagger.dart';
4
5future<void> main() async {
6  // Create the server
7  final pod = Serverpod(
8    args,
9    [
10      // Your endpoint classes
11    ],
12  );
13  
14  // Add the Swagger UI route for the current version
15  pod.webServer.addRoute(
16    SwaggerUIRoute(
17      Directory(Directory.current.path),
18      mountPath: '/swagger/',
19      apiSpecPath: 'apispec.json',
20      title: 'API Documentation (Current)',
21      customCssUrl: '/custom/swagger.css',
22      persistAuthorization: true,
23      tryItOutEnabled: true,
24    ),
25  );
26  
27  // Add the Swagger UI route for the v1 version
28  pod.webServer.addRoute(
29    SwaggerUIRoute(
30      Directory(Directory.current.path),
31      mountPath: '/swagger/v1/',
32      apiSpecPath: 'apispec.v1.json',
33      title: 'API Documentation (v1)',
34      customCssUrl: '/custom/swagger.css',
35      persistAuthorization: true,
36      tryItOutEnabled: true,
37    ),
38  );
39  
40  // Start the server
41  await pod.start();
42}

Step 4: Generate OpenAPI specifications for different versions

# Generate current version
dart run serverpod_swagger:generate --output=apispec.json --title="My API" --version="2.0.0"

# Generate v1 version
dart run serverpod_swagger:generate --output=apispec.v1.json --title="My API (v1)" --version="1.0.0"

Example with Custom Schemas

This example shows how to define custom schemas for complex types that aren't automatically handled by the generator.

Step 1: Create custom schema definitions

openapi_schemas.yaml
1schemas:
2  GeoPoint:
3    type: object
4    properties:
5      latitude:
6        type: number
7        format: double
8      longitude:
9        type: number
10        format: double
11    required:
12      - latitude
13      - longitude
14  
15  Address:
16    type: object
17    properties:
18      street:
19        type: string
20      city:
21        type: string
22      state:
23        type: string
24      zipCode:
25        type: string
26      country:
27        type: string
28      location:
29        $ref: '#/components/schemas/GeoPoint'
30    required:
31      - street
32      - city
33      - state
34      - zipCode
35      - country

Step 2: Use the custom types in your endpoints

location_endpoint.dart
1/// Get nearby locations
2/// 
3/// Returns a list of locations near the specified coordinates
4('/locations/nearby')
5Future<List<Location>> getNearbyLocations(
6  Session session,
7  ('latitude') double latitude,
8  ('longitude') double longitude,
9  ('radius') double radius,
10);
11
12/// Add a new address
13/// 
14/// Adds a new address to the user's profile
15('/users/addresses')
16Future<Address> addAddress(
17  Session session,
18  ('address') Address address,
19);

Example with File Upload

This example shows how to document file upload endpoints in your OpenAPI specification.

Step 1: Create a custom schema for file uploads

openapi_file_upload.yaml
1paths:
2  /users/avatar:
3    post:
4      summary: Upload user avatar
5      description: Uploads a new avatar image for the user
6      operationId: uploadAvatar
7      security:
8        - BearerAuth: []
9      requestBody:
10        content:
11          multipart/form-data:
12            schema:
13              type: object
14              properties:
15                avatar:
16                  type: string
17                  format: binary
18                  description: The avatar image file
19              required:
20                - avatar
21      responses:
22        '200':
23          description: Avatar uploaded successfully
24          content:
25            application/json:
26              schema:
27                type: object
28                properties:
29                  success:
30                    type: boolean
31                  avatarUrl:
32                    type: string
33        '400':
34          description: Invalid file format
35        '401':
36          description: Unauthorized

Step 2: Implement the file upload endpoint

user_endpoint.dart
1/// Upload user avatar
2/// 
3/// Uploads a new avatar image for the user
4('/users/avatar')
5Future<Map<String, dynamic>> uploadAvatar(Session session) async {
6  // Get the uploaded file from the request
7  final request = session.request!;
8  if (!request.isMultipart) {
9    session.response.statusCode = 400;
10    return {'success': false, 'error': 'Not a multipart request'};
11  }
12
13  // Process the multipart request
14  await for (final part in request.multipartFormData) {
15    if (part.name == 'avatar' && part.filename != null) {
16      // Read the file data
17      final bytes = await part.readBytes();
18      
19      // Save the file (implementation depends on your storage solution)
20      final avatarUrl = await saveAvatarFile(bytes, part.filename!);
21      
22      return {
23        'success': true,
24        'avatarUrl': avatarUrl,
25      };
26    }
27  }
28
29  session.response.statusCode = 400;
30  return {'success': false, 'error': 'No avatar file found'};
31}

More Examples

Explore more specific examples: