Code examples and good practices using Domain Drive Development, Hexagonal Architecture, CQRS, Symfony 6, PHP8 and anything else I can think of...
Code examples and good practices using Domain Drive Development, Hexagonal Architecture, CQRS,
Symfony 6, PHP8 and anything else I can think of...
Report Bug
·
Request Feature
I have created this project to have a guide of code examples and good practices as a future reference for me and for anyone who may be interested.
I will be adding more examples that I think are interesting and that provide an extra for anyone who wants to get started in the technologies mentioned bellow.
Features
Upcoming Features
I will add new features and examples, this project is constantly evolving! You can see unreleased code at here
Clone repo, download deps and create docker services:
git clone https://github.com/masfernandez/symfony-ddd-hexarch-cqrs.git
cd symfony-ddd-hexarch-cqrs
make composer-install
make up
Execute at root path:
make prod-start
In order to create a new Album
is mandatory to include a valid Token
in request's Authorization header. So first, let's create a new User:
make create-demo-user
# Credentials for demo user: [email protected] 1234567890
Now, it's time to get a valid token:
curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/authentication' \
-H 'Content-Type: application/json' \
--data-raw '{
"email": "[email protected]",
"password": "1234567890"
}'
You can find the Token in response's Location header:
Server: nginx/1.19.5
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.0.0
Location: 4ac71eeda13c8fe7f0e4c017412bd9f2d886288cb8c88331007f2a9c7652385b
Cache-Control: no-cache, private
Date: Fri, 15 Jan 2021 11:23:45 GMT
X-Robots-Tag: noindex
Strict-Transport-Security: max-age=31536000
{}
We can publish new Albums now: (replace the value of the token here with the one you got before... obviously)
curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/albums' \
-H 'Authorization: Bearer 4ac71eeda13c8fe7f0e4c017412bd9f2d886288cb8c88331007f2a9c7652385b' \
-H 'Content-Type: application/json' \
--data-raw '{
"id": "0da69030-3ed7-42b5-8aa5-25fb61dab1b2",
"title": "Abbey Road",
"release_date": "1969-09-26 00:00:00"
}'
Verifying the Album created:
curl -X GET 'http://api.musiclabel.127.0.0.1.nip.io/albums?page[number]=1&page[size]=1&sort=title&fields[albums]=id,title,release_date'
We need a JWToken to make PUT operations on Albums, so let's get one:
curl -i -X POST 'http://api.musiclabel.127.0.0.1.nip.io/authentication/jwt' \
-H 'Content-Type: application/json' \
--data-raw '{
"email": "[email protected]",
"password": "1234567890"
}'
You can find the JWToken (header.payload.signature) in response's headers:
HTTP/2 201
server: nginx/1.19.8
content-type: application/json
location: header+payload:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwOi8vZXhhbXBsZS5vcmciLCJqdGkiOiJlWFZocHBTR0JwZllTeHNZIiwiaWF0IjoxNjE3MzU1NTMyLjQyNzU3MSwibmJmIjoxNjE3MzU1NTMzLjQyNzU3MSwiZXhwIjoxNjE3MzU5MTMyLjQyNzU3MSwidWlkIjoiMGY4MzNjMjItZmVmZC00ZmFmLWE3YzItNGEwNzlhMjJjMzdjIn0
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:25:32 GMT
x-robots-tag: noindex
set-cookie: signature=GFZiEgVkKIbv5YszK_5wKmhLpqlkhYUUS1N1nCLLavs; path=/; secure; httponly; samesite=none
strict-transport-security: max-age=31536000
You may be asking why sending the JWToken like this... well, I'm to lazy to write hundred of words when there is a lot of information already on there. Just few tips:
Recommend read:
Don't forget the purpose of this repo: just to show some examples, crazy dev ideas and my opinionated vision on how to approach some scenarios ;)
Let's replace Album created before:
The client (React, Vue, Curl, Postman... whatever) should know how to re-construct the JWToken to make a request (remember, header + payload in Authorization header and signature in cookie)
Note: replace the values of the token here with the one you got before... obviously
curl -i -X PUT 'http://api.musiclabel.127.0.0.1.nip.io/albums/0da69030-3ed7-42b5-8aa5-25fb61dab1b2' \
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwOi8vZXhhbXBsZS5vcmciLCJqdGkiOiJlWFZocHBTR0JwZllTeHNZIiwiaWF0IjoxNjE3MzU1NTMyLjQyNzU3MSwibmJmIjoxNjE3MzU1NTMzLjQyNzU3MSwiZXhwIjoxNjE3MzU5MTMyLjQyNzU3MSwidWlkIjoiMGY4MzNjMjItZmVmZC00ZmFmLWE3YzItNGEwNzlhMjJjMzdjIn0' \
-H 'Content-Type: application/json' \
-H 'Cookie: signature=GFZiEgVkKIbv5YszK_5wKmhLpqlkhYUUS1N1nCLLavs' \
--data-raw '{
"title": "New album value here",
"release_date": "2021-04-02 00:00:00"
}'
Response:
HTTP/2 204
server: nginx/1.19.8
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:58:22 GMT
x-robots-tag: noindex
strict-transport-security: max-age=31536000
Verifying the Album updated:
curl -i -X GET 'http://api.musiclabel.127.0.0.1.nip.io/albums?page[number]=1&page[size]=1&sort=title&fields[albums]=id,title,release_date'
Response:
HTTP/2 200
server: nginx/1.19.8
content-type: application/json
x-powered-by: PHP/8.0.3
cache-control: no-cache, private
date: Fri, 02 Apr 2021 09:59:36 GMT
x-robots-tag: noindex
strict-transport-security: max-age=31536000
{
"data": [
{
"id": "0da69030-3ed7-42b5-8aa5-25fb61dab1b2",
"title": "New album value here",
"release_date": "2021-04-02 00:00:00"
}
],
"links": {
"self": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
"first": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
"prev": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
"next": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1",
"last": "\/albums?page%5Bnumber%5D=1&page%5Bsize%5D=1"
},
"meta": {
"total_pages": 1
}
}
Several docker services will be available and ready for use when the app starts:
RabbitMQ
http://localhost:15672
user: rabbit_user
password: rabbit_pass
Kibana
Kibana Nginx logs configuration:
Execute below command after all ELK services are started:
make filebeat-dashboards
Go to http://localhost:5601/app/dashboards and search for "Nginx"
Kibana Symfony logs configuration:
Create an index pattern at http://localhost:5601/app/management/kibana/indexPatterns/create
Configure logs
Logs can be visualized now at http://localhost:5601/app/logs/stream
make dev-start
make test
There are several services in the Docker stack for this project. All services are built from official docker images except:
See the open issues for a list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)Distributed under the MIT License. See LICENSE.txt
for more information.
Miguel Ángel Sánchez Fernández - [email protected]
(linkedin hiden profile - require login)
Project Link: https://github.com/masfernandez/symfony-ddd-hexarch-cqrs