Quickstart: Build Your First Winter Boot Microservice
This guide walks you through building a minimal but complete Winter Boot microservice from scratch. By the end you will have a running HTTP server, a managed service bean, and a REST endpoint you can hit with curl. All you need is PHP 8.4+, Composer, and the Swoole extension.
-
Install PHP and Swoole
Ensure PHP 8.4 or later is installed, then install the Swoole extension for the built-in async HTTP server:
Terminal window pecl install swooleConfirm both are available:
Terminal window php -vphp -r "echo phpversion('swoole');" -
Require the Composer Packages
Create a new directory for your project and initialise it with Composer, then pull in the core framework package. The optional
winter-modulespackage adds community integrations (Redis, Kafka, Doctrine ORM, and more).Terminal window mkdir my-service && cd my-servicecomposer init --no-interactioncomposer require suvera/winter-bootcomposer require suvera/winter-modules # optional -
Create the Directory Structure
Winter Boot expects a
config/directory forapplication.ymland asrc/directory for your PHP classes. A minimal layout looks like this:my-service/├── composer.json├── config/│ └── application.yml├── src/│ ├── GreetingService.php│ └── GreetingController.php└── Application.php -
Write application.yml
Create
config/application.yml. At minimum you need a server port. Thewinter.applicationblock gives your service a human-readable name and version that surface in health and metrics endpoints.config/application.yml server:port: 8080address: 127.0.0.1winter:application:name: My Greeting Serviceid: greeting-serviceversion: 1.0.0-DEV -
Create a Service Bean
Annotate a class with
#[Service]to register it as a managed bean. Winter Boot will instantiate it, inject its dependencies, and make it available for#[Autowired]injection throughout the application context.src/GreetingService.php <?phpdeclare(strict_types=1);namespace com\example\myapp;use dev\winterframework\stereotype\Service;#[Service]class GreetingService{public function greet(string $name): string{return sprintf('Hello, %s! Welcome to Winter Boot.', $name);}} -
Create a REST Controller
Annotate a class with
#[RestController]and map an HTTP route with#[GetMapping]. Inject the service bean via#[Autowired]. Return aResponseEntityto control the HTTP status code and response body.src/GreetingController.php <?phpdeclare(strict_types=1);namespace com\example\myapp;use dev\winterframework\stereotype\Autowired;use dev\winterframework\stereotype\RestController;use dev\winterframework\stereotype\web\GetMapping;use dev\winterframework\stereotype\web\RequestParam;use dev\winterframework\web\http\ResponseEntity;#[RestController]class GreetingController{#[Autowired]private GreetingService $greetingService;#[GetMapping(path: '/api/v1/greet')]public function greet(#[RequestParam] string $name = 'World'): ResponseEntity {$message = $this->greetingService->greet($name);return ResponseEntity::ok()->withJson(['message' => $message]);}} -
Create the Application Entry Point
The entry-point class carries the
#[WinterBootApplication]attribute, which tells the framework where to find your configuration and which namespaces to scan for beans.configDirectory— directories containingapplication.ymland any other config files.scanNamespaces— pairs of[NamespacePrefix, BaseDirectory]the scanner should inspect.
Application.php <?phpdeclare(strict_types=1);use dev\winterframework\stereotype\WinterBootApplication;use dev\winterframework\core\app\WinterWebSwooleApplication;require_once __DIR__ . '/vendor/autoload.php';#[WinterBootApplication(configDirectory: [__DIR__ . '/config'],scanNamespaces: [['com\\example\\myapp', __DIR__ . '/src']])]class Application{public static function main(): void{(new WinterWebSwooleApplication())->run(Application::class);}}Application::main(); -
Run the Application
Start the server by executing the entry point with PHP. Swoole will fork worker processes and begin accepting HTTP connections on the port defined in
application.yml.Terminal window php Application.phpYou should see output similar to:
Http server started on 127.0.0.1:8080, pid:12345, master_pid:12344 -
Test with curl
In a separate terminal, send a request to the greeting endpoint:
Terminal window curl "http://127.0.0.1:8080/api/v1/greet?name=Alice"Expected response:
{"message": "Hello, Alice! Welcome to Winter Boot."}Test the default parameter:
Terminal window curl "http://127.0.0.1:8080/api/v1/greet"{"message": "Hello, World! Welcome to Winter Boot."}
What’s Next?
Section titled “What’s Next?”Now that your service is running, explore these topics to build on the foundation:
application.yml, #[Value], and additional property sources.#[PostConstruct] lifecycle hooks.#[Transactional].#[Async] and #[Scheduled].