English | Bahasa Indonesia
DelphiAPIStarterKit is a Delphi WebBroker starter template for building REST APIs and web services with a clean backend structure: RTTI-based routing, response helpers, request validation, service layer, repository layer, FireDAC connection factory, and practical CRUD modules.
This project is intended as a reusable foundation for Delphi backend APIs. It is not a production-ready deployment template without additional configuration and security review.
- Delphi WebBroker API server.
- RTTI-based route dispatch from URL resources to registered endpoint classes.
- FireDAC database access for MySQL/MariaDB.
- Module structure based on
RestAPI,Service,Repository,Validator, andDTOunits. - Standard JSON response envelope.
- Authentication example with sessions and access tokens.
- Example modules:
- Auth
- Users
- Category
- Product
- Customer
- Sample database schema in
assets/databases/demo_delphirest.sql. - API documentation and Postman collection are available under
docs/apiif the docs folder is published.
- Delphi with WebBroker, FireDAC, FireDAC MySQL driver, and the standard Indy/WebBroker bridge units.
- IPPeer runtime units if your Delphi installation separates these dependencies.
- MySQL or MariaDB server.
- MySQL/MariaDB native client library matching the application target architecture.
- Windows for the default
Win32build target. - Linux64 is enabled in the Delphi project and requires the Delphi Linux toolchain/PAServer setup.
The default build script targets Debug | Win32. Use environment variables to change the Delphi environment script, build configuration, or platform.
sources/
app/ WebBroker module and server bootstrap
core/ Core routing, response, request, constants, config
infrastructure/
database/ FireDAC connection factory and query helper
security/ Token/security helper
modules/
auth/ Auth endpoint, service, repository, validator, DTO
users/ User endpoint, service, repository, validator, DTO
category/ Category endpoint, service, repository, validator, DTO
products/ Product endpoint, service, repository, validator, DTO
customers/ Customer endpoint, service, repository, validator, DTO
shared/
helpers/ Reusable helpers
assets/
databases/
demo_delphirest.sql MySQL/MariaDB sample schema
API responses use this envelope:
{
"status": 200,
"messages": "OK",
"servertime": "1780962999",
"data": []
}For error responses, status follows the HTTP status code and data is returned as an array containing an empty object.
The database connection is not stored in source code. Configure it before running the server.
Preferred option: set environment variables:
setx DELPHI_API_DB_SERVER "localhost"
setx DELPHI_API_DB_DATABASE "demo_delphirest"
setx DELPHI_API_DB_USER "root"
setx DELPHI_API_DB_PASSWORD ""Alternative option: create config.ini in the application base directory:
[Database]
Server=localhost
Database=demo_delphirest
User_Name=root
Password=
CharacterSet=utf8mb4
POOL_MaximumItems=50
POOL_ExpireTimeout=300000Use config.example.ini as the template. Do not commit your real config.ini.
Create the database:
mysql -u root -p -e "CREATE DATABASE demo_delphirest CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"Import the schema:
mysql -u root -p demo_delphirest < assets\databases\demo_delphirest.sqlIf PowerShell causes redirect issues, run the command through cmd:
cmd /c "mysql -u root -p demo_delphirest < assets\databases\demo_delphirest.sql"- Open phpMyAdmin.
- Create a database named
demo_delphirest. - Select the database.
- Open the
Importtab. - Select
assets/databases/demo_delphirest.sql. - Run the import.
- The sample schema targets MySQL/MariaDB with InnoDB and
utf8mb4. - During setup, the database account needs permission to create/import tables.
- At runtime, use a dedicated application account with only the required CRUD permissions for the application database.
- The schema file creates tables only. If you need test login data, insert a demo role and user that match your configured
DELPHI_API_HMAC_SECRET.
The HMAC signature secret is not stored in source code. Configure it before using login, password hashing, token creation, or token validation.
Preferred option: set an environment variable:
setx DELPHI_API_HMAC_SECRET "replace-with-a-long-random-secret"For the current terminal session only:
set DELPHI_API_HMAC_SECRET=replace-with-a-long-random-secretAlternative option: create config.ini in the application base directory:
[Security]
HMACSecret=replace-with-a-long-random-secretUse config.example.ini as the template. Do not commit your real config.ini.
FireDAC MySQL requires a native client library that matches the application bitness:
- A
Win32application requires a 32-bit client library. - A
Win64application requires a 64-bit client library. - A
Linux64deployment requires a compatible 64-bitlibmysqlclient.soorlibmariadb.soavailable on the Linux server.
Do not download libmysql.dll from unofficial DLL mirrors. Use one of these official sources:
- MySQL C API / libmysqlclient: https://dev.mysql.com/downloads/c-api/
- MySQL Connector/C++ package: https://dev.mysql.com/downloads/connector/cpp/
- MariaDB Connector/C: https://mariadb.com/docs/connectors/mariadb-connector-c
MariaDB Connector/C can connect to MySQL and MariaDB, and MariaDB documents the C connector as LGPLv2.1 licensed.
Simple setup:
- Download the MySQL/MariaDB client library from an official source.
- Choose the same architecture as your Delphi build target.
- Extract
libmysql.dllfrom the package. - Place
libmysql.dllin the same folder as the executable, for example:
bin/libmysql.dll
Alternatively, place the DLL directory in the Windows PATH.
If you run from the IDE and the current directory is different, make sure VendorHome points to the directory containing the DLL. The current Windows startup code sets:
DM.FDPhysMySQLDriverLink.VendorHome := GetCurrentDir;This means the application looks for the native client library from the current directory. If the DLL is stored elsewhere, adjust VendorHome in the startup code.
For an open-source repository, the recommended approach is not to commit libmysql.dll or binary ZIP files. Document the dependency and let users install the client library from the official vendor package.
For Linux64 deployment, install the MySQL/MariaDB client library on the target server using the server distribution package manager or the official vendor package.
The current Linux startup code sets:
DM.FDPhysMySQLDriverLink.VendorHome := '/www/server/mysql/';If your Linux server stores the client library in a different location, adjust VendorHome in DelphiAPIStarterKit.dpr or adapt the startup code to read this path from deployment configuration.
Default build script:
compile.batThe script:
- Stops
DelphiAPIStarterKit.exeif it is already running. - Calls
rsvars.batfromDELPHI_RSVARS, or from%BDS%\bin\rsvars.batwhen running inside a Delphi command prompt. - Builds the project via MSBuild.
- Defaults to
Debug | Win32.
When running from a normal terminal, set DELPHI_RSVARS first:
set DELPHI_RSVARS=C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\rsvars.bat
compile.batOptional build overrides:
set BUILD_CONFIG=Release
set BUILD_PLATFORM=Win64
compile.batLinux64 build example:
set BUILD_CONFIG=Release
set BUILD_PLATFORM=Linux64
compile.batLinux builds require a configured Delphi Linux toolchain and PAServer connection.
Manual build:
msbuild DelphiAPIStarterKit.dproj /t:Make /p:Config=Debug /p:Platform=Win32 /nologo /v:minimalAfter building, run the executable from the output folder. Make sure:
- MySQL/MariaDB server is running.
- The
demo_delphirestdatabase exists and the schema has been imported. - The MySQL client DLL is available to FireDAC.
- The server port is not already used by another application.
Default local base URL:
http://localhost:9381
Import the Postman collection:
docs/api/postman.collection.json
Set the collection variable:
base_url = http://localhost:9381/
Login request example:
curl -X POST http://localhost:9381/api/v1/Auth/Login ^
-H "Content-Type: application/json" ^
-d "{\"username\":\"demo_admin\",\"password\":\"demo_admin\",\"device_id\":\"local-dev\",\"device_name\":\"CLI\"}"The database schema does not insert a default demo user. Create your own local test user before expecting the login example to succeed.
All endpoints under User, Product, Category, and Customer require an access token from the login response. Pass the token via the x-api-token header:
x-api-token: <access_token>
The server also accepts access-token and Authorization: Bearer <token> as fallback header names.
Base route:
/api/v1/{resource}
Examples:
POST /api/v1/auth/Login
POST /api/v1/auth/Refresh
POST /api/v1/auth/Logout
GET /api/v1/users
POST /api/v1/users
PUT /api/v1/users/{user_id}
DELETE /api/v1/users/{user_id}
GET /api/v1/category
GET /api/v1/products
GET /api/v1/customers
Routes are resolved to registered endpoint classes using a lightweight RTTI-based dispatcher. The dispatcher builds the target class name from the API version and resource name:
TRestClass{APIVersion}{RequestClass}
Example:
/api/v1/users -> TRestClassV1User
Internally, the core dispatcher uses FindClass to locate the registered endpoint class, creates an instance, and invokes its Route method. The endpoint Route method then maps the HTTP method and path to the proper service action.
Example: adding an orders resource.
sources/modules/orders/
Example file:
sources/modules/orders/Order.DTO.pas
Keep request and response records explicit:
type
TOrderCreateRequest = record
CustomerID: string;
OrderDate: TDateTime;
Notes: string;
end;Example file:
sources/modules/orders/Order.Validator.pas
The validator reads and validates the TFDMemTable request before business logic runs.
Use existing helpers where possible:
THelperValidator.GetRequiredString(...)
THelperValidator.GetOptionalString(...)
THelperValidator.ParseIntegerField(...)Example file:
sources/modules/orders/Order.Repository.pas
Repositories should contain database access only. Use parameterized queries:
TQueryFunction.SQLAdd(LDataset,
'INSERT INTO orders (order_id, customer_internal_id, notes) VALUES (:order_id, :customer_id, :notes)',
True
);
TQueryFunction.SQLParamByName(LDataset, 'order_id', AOrderID);
TQueryFunction.SQLParamByName(LDataset, 'customer_id', ACustomerID);
TQueryFunction.SQLParamByName(LDataset, 'notes', ANotes);
TQueryFunction.ExecSQL(LDataset);Do not concatenate raw user input into SQL.
Example file:
sources/modules/orders/Order.Service.pas
Services contain business logic, transaction handling, and repository calls.
Write operation pattern:
FConnection.StartTransaction;
try
FRepository.CreateOrder(...);
FConnection.Commit;
except
on E: Exception do begin
THelperTransaction.Rollback(FConnection);
Exit(InternalServerError);
end;
end;Example file:
sources/modules/orders/RestAPI.Order.pas
The class must match the route naming pattern:
type
TRestClassV1Order = class(TPersistent)
public
function Route(AConnection: TFDConnection; AData: TFDMemTable;
AWebAction: TWebActionItem; ARequest: TWebRequest;
AResponse: TWebResponse; out AStatusCode: Integer): string;
end;Inside Route, use THelperEndpoint.ExecuteRoute like the existing modules.
Add the new unit to the uses clause in:
sources/core/BFA.Core.Rest.pas
Then register the class in RegisterClassAPI. This step is required because the RTTI dispatcher resolves endpoint classes through Delphi's class registry:
RegisterClassAPI([TRestClassV1User, TRestClassV1Auth, TRestClassV1Product,
TRestClassV1Category, TRestClassV1Customer, TRestClassV1Order]);Add the new units to:
DelphiAPIStarterKit.dprDelphiAPIStarterKit.dproj
If you use the Delphi IDE, add the units through the Project Manager so the .dproj file is updated.
Create a migration/schema update in the database assets or migration docs.
Example:
CREATE TABLE `orders` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`order_id` CHAR(36) NOT NULL,
`customer_internal_id` BIGINT UNSIGNED NOT NULL,
`notes` VARCHAR(255) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_orders_public_id` (`order_id`),
KEY `idx_orders_customer` (`customer_internal_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;Add endpoint documentation:
docs/api/orders.md
Update the Postman collection if used:
docs/api/postman.collection.json
The sample schema contains:
m_roleusersuser_sessionaccess_tokencategoryproductcustomer
Import the schema from:
assets/databases/demo_delphirest.sql
Before production use:
- Move database credentials to config/environment variables.
- Configure
DELPHI_API_HMAC_SECRETor[Security] HMACSecretinconfig.ini. - Review the password hashing strategy. The starter currently uses HMAC-SHA256 with an application secret for simplicity; production systems should use a password hashing algorithm such as bcrypt, Argon2, or PBKDF2 with per-user salts and an appropriate work factor.
- Do not expose stack traces, SQL text, tokens, passwords, or secrets in responses/logs.
- Run the API behind HTTPS.
- Restrict CORS to trusted application domains.
- Give the MySQL user only the permissions it needs.
The project source code uses the license provided in LICENSE.
Third-party dependencies such as MySQL/MariaDB client libraries follow their vendor licenses and should not be committed directly into this repository.
See CONTRIBUTING.md for development setup, coding standards, build validation, and documentation expectations.
See SECURITY.md for vulnerability reporting and security review guidance.
See CHANGELOG.md for unreleased changes and release notes.