Exercise 10: TypeScript Type Generation with Mockserver Admin
10.1 Overview: Type-Safe Mock Data Development
Exercise 10 demonstrates how to leverage @sap-ux/fe-mockserver-admin to automatically generate TypeScript type definitions from your OData metadata. This provides:
- Type safety for mock data development
- IntelliSense support in your IDE
- Compile-time validation of mock data structures
- Automated type generation from OData metadata
The fe-mockserver-admin package analyzes your service metadata and generates corresponding TypeScript interfaces, eliminating manual type definitions and ensuring consistency with your actual OData service.
10.2 Package Installation and Setup
Exercise 10 includes the required dependencies and scripts for type generation:
Key Dependencies in package.json:
{
"devDependencies": {
"@sap-ux/fe-mockserver-admin": "0.0.14",
"typescript": "^5.9.3",
"ts-node": "^10.9.2"
},
"scripts": {
"generate-entity-files": "fe-mockserver-admin generate-entity-files -m ./webapp/localService/mainService/metadata.xml --output ./webapp/localService/mainService/data",
"generate-types": "fe-mockserver-admin generate-types -m ./webapp/localService/mainService/metadata.xml --output ./webapp/localService/mainService/data"
}
}
10.3 TypeScript Configuration
The tsconfig.json is configured for optimal mock data development:
{
"compilerOptions": {
"target": "es2022",
"module": "commonjs",
"skipLibCheck": true,
"allowJs": true,
"sourceMap": true,
"strict": false,
"strictPropertyInitialization": false,
"moduleResolution": "node",
"rootDir": "./webapp",
"noEmitOnError": false,
"baseUrl": "./"
}
}
10.4 Automatic Type Generation from Metadata
Generate TypeScript types from your OData metadata:
npm run generate-types
This command analyzes metadata.xml and creates comprehensive type definitions:
Generated Files Structure:
// ====== Entity Types ======
// Type definitions for Books
export type Books = {
createdAt?: string;
createdBy?: string;
modifiedAt?: string;
modifiedBy?: string;
ID: string;
title?: string;
author?: string;
price?: number;
currency_code?: string;
stock?: number;
description?: string;
coverUrl?: string;
IsActiveEntity: boolean;
HasActiveEntity: boolean;
HasDraftEntity: boolean;
currency?: NavPropTo;
chapters?: NavPropTo;
reviews?: NavPropTo;
DraftAdministrativeData?: NavPropTo;
SiblingEntity?: NavPropTo;
}
export type BooksKeys = {
ID: string;
IsActiveEntity: boolean;
}
// ====== Complex Types ======
// Type definitions for return_BookshopService_Books_setDiscount
export type return_BookshopService_Books_setDiscount = {
message?: string;
newPrice?: number;
}
10.5 Type-Safe Mock Data Development
With generated types, you can create type-safe mock data files:
Example: Type-safe Books.ts mock data:
import type {
ODataRequest,
Action,
NavigationProperty,
PartialReferentialConstraint,
} from '@sap-ux/ui5-middleware-fe-mockserver';
import { MockDataContributorClass } from '@sap-ux/ui5-middleware-fe-mockserver';
import type {
Books,
BooksKeys,
return_BookshopService_Books_promoteBook,
return_BookshopService_Books_setDiscount,
} from './ODataTypes';
export default class BooksContributor extends MockDataContributorClass {
getInitialDataSet(contextId: string): Books[] {
const books = [];
const authors = ['Jane Austen', 'Mark Twain', 'Charles Dickens', 'Ernest Hemingway', 'Virginia Woolf'];
const genres = ['Fiction', 'Mystery', 'Romance', 'Science Fiction', 'Biography'];
for (let i = 0; i < 20; i++) {
const randomAuthor = authors[Math.floor(Math.random() * authors.length)];
const randomGenre = genres[Math.floor(Math.random() * genres.length)];
books.push({
ID: `550e8400-e29b-41d4-a716-44665544${String(i).padStart(4, '0')}`,
title: `${randomGenre} Book ${i + 1}`,
author: randomAuthor,
price: Math.floor(Math.random() * 50) + 10,
currency_code: Math.random() > 0.5 ? 'EUR' : 'USD',
stock: Math.floor(Math.random() * 100),
description: `A compelling ${randomGenre.toLowerCase()} story by ${randomAuthor}.`,
coverUrl: `https://picsum.photos/300/400?random=${i}`,
createdAt: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(),
createdBy: 'admin',
modifiedAt: new Date().toISOString(),
modifiedBy: 'admin',
IsActiveEntity: true,
HasActiveEntity: false,
HasDraftEntity: Math.random() > 0.8, // 20% chance of being in draft
});
}
return books;
}
async setDiscount(_actionDefinition: Action, actionData: BooksAction_setDiscountData, keys: BooksKeys, odataRequest: ODataRequest): Promise {
// Simple validation example - discount cannot exceed 90%
if (actionData.percentage > 90) {
this.throwError('Discount cannot exceed 90%', 400, {
error: {
code: 'INVALID_DISCOUNT',
message: 'Company policy: Maximum discount is 90%',
},
});
}
// Normal business logic continues...
const currentEntries = await this.base.fetchEntries(keys, odataRequest);
if (currentEntries.length > 0) {
const currentBook = currentEntries[0];
const discountPercentage = actionData.percentage || 10; // Default 10% if not provided
const discountMultiplier = (100 - discountPercentage) / 100;
const newPrice = Math.round(currentBook.price * discountMultiplier * 100) / 100;
// Update the book with new price
await this.base.updateEntry(keys, { price: newPrice }, odataRequest);
return {
message: `${discountPercentage}% discount applied to "${currentBook.title}"`,
newPrice: newPrice,
};
}
}
}
10.6 Benefits of Type-Safe Mock Development
1. Compile-Time Validation
// ❌ TypeScript catches errors at compile time
const invalidBook: Books = {
ID: "123",
price: "invalid", // Error: Type 'string' is not assignable to type 'number'
IsActiveEntity: true,
HasActiveEntity: false,
HasDraftEntity: false
};
2. IntelliSense Support
- Auto-completion for entity properties
- Type hints for action parameters and return types
- Navigation property type safety
3. Metadata Synchronization
- Types automatically reflect metadata changes
- Consistent data structures across all mock files
10.7 Integration with Existing Mockserver Workflows
The generated TypeScript files work seamlessly with the existing mockserver:
Standard ui5-mock.yaml Configuration:
- name: sap-fe-mockserver
beforeMiddleware: csp
configuration:
services:
- urlPath: /bookshop
metadataPath: ./webapp/localService/mainService/data
generateMockData: false
10.8 Running Exercise 10
Start the application with TypeScript-generated mock data:
npm run start:ex10
What you'll experience:
- Type-safe mock data loaded from
.tsfiles - Consistent data structure matching your OData service
- Full IntelliSense support during development
- Compile-time validation of all mock data
10.9 Best Practices
1. Regenerate Types After Metadata Changes
# After updating metadata.xml
npm run generate-types
2. Version Control Strategy
- Include:
ODataTypes.d.tsand other generated type files - Exclude: Generated
.jsfiles (if using ts-node)
3. Development Workflow
- Update service metadata
- Regenerate types with
npm run generate-types - Update mock data files with TypeScript validation
- Test with
npm run start:ex10
10.10 Key Learning Points
✅ Automated Type Generation: No manual type definitions needed
✅ Metadata Synchronization: Types stay in sync with OData service
✅ IDE Integration: Full IntelliSense and error checking
✅ Compile-Time Safety: Catch data structure errors before runtime
✅ Navigation Properties: Proper typing for complex relationships
✅ Draft Support: Built-in SAP Fiori draft entity handling
Next Level: Combine type-safe mock data with the JavaScript logic patterns from Exercise 3 for the most robust mock data development experience.