SlideShare a Scribd company logo
1 of 43
Download to read offline
SERIAL(IZE) KILLERS
czyli jak popsuliśmy API
Piotr Horzycki / Espeo Software / peterdev.pl
PROSTA ENCJA
class Product
{
public function __construct(
public readonly string $id,
public readonly string $name,
public readonly string $price,
public readonly string $editedBy,
) {
}
}
SERIALIZE(), CZYLI ZŁO
$code = serialize($product);
O:7:"Product":4:{s:2:"id";s:3:"123";s:4:"name";s:8:"Chainsaw";
s:5:"price";s:10:"EUR 123.45";s:8:"editedBy";s:4:"John";}
$product = unserialize($code);
MAŁY PATCH, DUŻY PROBLEM
ramsey/uuid 4.2.1
ramsey/uuid 4.2.2
$id = RamseyUuidUuid::uuid4();
C:35:"RamseyUuidLazyLazyUuidFromString":36:{23dc5ed8-4b73-4df8-9421-95e5c07a58e5}
O:35:"RamseyUuidLazyLazyUuidFromString":1:{s:6:"string";s:36:"4fdf0133-12be-4089-8fe5-45b4a3e2b
PROBLEM Z BEZPIECZEŃSTWEM
https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=unserialize
https://redfoxsec.com/blog/insecure-deserialization-in-php/
https://owasp.org/www-
community/vulnerabilities/PHP_Object_Injection
KIEDYŚ TO BYŁO...
{
"example": {
"key": "value"
}
}
$request = json_decode(file_get_contents('php://input'));
$price = $request['price'];
$name = $request['name'] ?? '';
KIEDY WYMYŚLONO SERIALIZER
$product = new Product('123', 'Chainsaw', 'EUR 123.45', 'John');
$json = $serializer->serialize($product);
{
"id": "123",
"name": "Chainsaw",
"price": "EUR 123.45",
"editedBy": "John"
}
$product = $serializer->deserialize($requestBody, Product::class, 'json');
KIEDY CHCEMY JESZCZE ORM
class Product
{
public function __construct(
#[ORMId, ORMColumn]
public readonly string $id,
#[ORMColumn]
public readonly string $name,
#[ORMColumn]
public readonly string $price,
#[ORMColumn]
public readonly string $editedBy,
) {
}
}
KIEDY FRONTEND CHCE COŚ ZMIENIĆ
class Product
{
public function __construct(
#[ORMId, ORMColumn]
public readonly string $id,
#[ORMColumn]
#[SerializedName("productName")]
public readonly string $name,
#[ORMColumn]
public readonly string $price,
#[ORMColumn]
public readonly string $editedBy,
) {
}
}
KIEDY FRONTEND CHCE RÓŻNE DANE
class Product
{
public function __construct(
#[ORMId, ORMColumn]
#[Groups(['admin', 'cart'])]
public readonly string $id,
#[ORMColumn]
#[Groups(['admin', 'cart'])]
#[SerializedName("productName")]
public readonly string $name,
#[ORMColumn]
#[Groups(['cart'])]
public readonly string $price,
#[ORMColumn]
#[Ignore]
public readonly string $editedBy,
) {
}
}
KIEDY FRONTEND CHCE COŚ EKSTRA
class Product
{
// ...
public function getUniversalAnswer(): int
{
return 42;
}
#[Ignore]
public function getImportantBusinessLogic(): int
{
return 2 * 2;
}
}
DORZUCANIE RZECZY POD STOŁEM
final class SneakyProductNormalizer implements NormalizerInterface
{
/** @param Product $object */
public function normalize(mixed $object, string $format = null, array $context = []): ar
{
return [
'id' => $object->id,
'name' => $object->name,
'price' => $object->price,
'extraField' => 2 * 2,
];
}
// ...
}
PERFORMANCE
100 pozycji na liście, 301 zapytań SQL...
ROZWIĄZANIE: DTO
class ProductAdminListDto
{
public function __construct(
public readonly string $id,
public readonly string $name,
) {
}
public static function fromEntity(Product $product): self
{
return new self($product->id, $product->name);
}
}
OBSŁUGA NULLI I WARTOŚCI
NIEZAINICJOWANYCH
class Product
{
public string $sku;
public ?string $rating = null;
}
OBSŁUGA NULLI I WARTOŚCI
NIEZAINICJOWANYCH
class Product
{
public string $sku;
public ?string $rating = null;
}
{
// "sku" pominięte, chyba że SKIP_UNINITIALIZED_VALUES = false
"rating": null // będzie pominięte dla SKIP_NULL_VALUES = true
}
HISTORIA TRUDNEJ MIGRACJI: JMS ->
SYMFONY
{
"type": "IP",
"value": "127.0.0.1",
"active": 123
}
HISTORIA TRUDNEJ MIGRACJI: JMS ->
SYMFONY
{
"type": "IP",
"value": "127.0.0.1",
"active": 123
}
$rule = $jms->deserialize($requestBody, Rule::class, 'json');
HISTORIA TRUDNEJ MIGRACJI: JMS ->
SYMFONY
{
"type": "IP",
"value": "127.0.0.1",
"active": 123
}
$rule = $jms->deserialize($requestBody, Rule::class, 'json');
W PHP mamy active === TRUE...
USZCZELNIAMY TYPY, PO CZYM KLIENT
ZGŁASZA BŁĄD...
Zadanie soft skill: wytłumacz klientowi, że się pomylił
{
"currency": "GBP",
"amount": "1234" // 🔥
}
CIĘŻKA PRZEPRAWA Z ENCJAMI
inne atrybuty JMS/Symfony
gąszcz ExclusionPolicy, Expose, Ignore
constructor property promotion, nulle itd.
BŁĘDY WALIDACJI TYPÓW W SYMFONY
try {
$dto = $serializer->deserialize($requestBody, Product::class, 'json', [
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
]);
} catch (PartialDenormalizationException $e) {
$violations = new ConstraintViolationList();
foreach ($e->getErrors() as $exception) {
// ...
}
return $this->json($violations, 400);
}
https://symfony.com/doc/current/components/serializer.html#collecting-type-errors-while-denormalizing
DODANIE NOWEGO POLA, A INTEGRACJA
KLIENTA
class Notification
{
public function __construct(
public readonly string $paymentId,
public readonly string $status,
public readonly string $receivedAt,
) {
}
}
DEVELOPERS BE LIKE...
"He he... broken... wait a minute..."
DODANIE NOWEGO POLA, A INTEGRACJA
KLIENTA
class NotificationV2
{
public function __construct(
public readonly string $paymentId,
public readonly string $status,
public readonly string $receivedAt,
public readonly int $version = 2,
) {
}
}
ŹLE NAZWANE POLE OPCJONALNE
Walidacja przechodzi, ale funkcjonalność nie działa
Rozwiązanie: ALLOW_EXTRA_ATTRIBUTES = false
{
"currency": "GBP",
"amount": 1234,
"optionalFieldWithTypo": "foo" // 🔥
}
POZIOMY TESTÓW API
POZIOMY TESTÓW API
nie ma żadnych
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
assert HTTP 200 (błędne dane)
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
assert HTTP 200 (błędne dane)
assert JSON contains
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
assert HTTP 200 (błędne dane)
assert JSON contains
assert JSON path equals
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
assert HTTP 200 (błędne dane)
assert JSON contains
assert JSON path equals
assert database contains
POZIOMY TESTÓW API
nie ma żadnych
assert HTTP 200 (happy path)
assert HTTP 200 (błędne dane)
assert JSON contains
assert JSON path equals
assert database contains
assert no side effects
PODZIAŁ ODPOWIEDZIALNOŚCI MIĘDZY
WARSTWAMI TESTÓW
jednostkowe
integracyjne
API
E2E
DOKUMENTACJA? A KOMU TO POTRZEBNE...
rozjazd między OpenAPI a implementacją
brak przykładów w dokumentacji
ciągłe pytania od frontendowców
TESTY KONTRAKTÓW
Spectator (Laravel)
Pact.io
PODSUMOWANIE
unikać serialize()
nawet drobna różnica w API może popsuć integrację
testować API, łącznie z nietypowymi sytuacjami
DTO jako pośrednik między encjami a endpointami
wersjonowanie lub konfiguracja per klient
dokumentacja, która żyje
DZIĘKUJĘ :)
peterdev.pl
SERIALIZE KILLERS: How we broke our API
SERIALIZE KILLERS: How we broke our API

More Related Content

Similar to SERIALIZE KILLERS: How we broke our API

Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...
Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...
Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...Mail.ru Group
 
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...Mail.ru Group
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix itRafael Dohms
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015Fernando Daciuk
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console componentHugo Hamon
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)James Titcumb
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 

Similar to SERIALIZE KILLERS: How we broke our API (20)

Intermediate PHP
Intermediate PHPIntermediate PHP
Intermediate PHP
 
Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...
Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...
Security Meetup 22 октября. «PHP Unserialize Exploiting». Павел Топорков. Лаб...
 
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
Security Meetup 22 октября. «Реверс-инжиниринг в Enterprise». Алексей Секрето...
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Oops in php
Oops in phpOops in php
Oops in php
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Smelling your code
Smelling your codeSmelling your code
Smelling your code
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 

More from Piotr Horzycki

Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karieręPiotr Horzycki
 
Architecture tests: Setting a common standard
Architecture tests: Setting a common standardArchitecture tests: Setting a common standard
Architecture tests: Setting a common standardPiotr Horzycki
 
Software development myths that block your career
Software development myths that block your careerSoftware development myths that block your career
Software development myths that block your careerPiotr Horzycki
 
Software Composition Analysis in PHP
Software Composition Analysis in PHP Software Composition Analysis in PHP
Software Composition Analysis in PHP Piotr Horzycki
 
How to count money with Java and not lose it
How to count money with Java and not lose itHow to count money with Java and not lose it
How to count money with Java and not lose itPiotr Horzycki
 
How to count money using PHP and not lose money
How to count money using PHP and not lose moneyHow to count money using PHP and not lose money
How to count money using PHP and not lose moneyPiotr Horzycki
 
New kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingNew kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingPiotr Horzycki
 
Time-driven applications
Time-driven applicationsTime-driven applications
Time-driven applicationsPiotr Horzycki
 
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPJak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPPiotr Horzycki
 

More from Piotr Horzycki (9)

Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karierę
 
Architecture tests: Setting a common standard
Architecture tests: Setting a common standardArchitecture tests: Setting a common standard
Architecture tests: Setting a common standard
 
Software development myths that block your career
Software development myths that block your careerSoftware development myths that block your career
Software development myths that block your career
 
Software Composition Analysis in PHP
Software Composition Analysis in PHP Software Composition Analysis in PHP
Software Composition Analysis in PHP
 
How to count money with Java and not lose it
How to count money with Java and not lose itHow to count money with Java and not lose it
How to count money with Java and not lose it
 
How to count money using PHP and not lose money
How to count money using PHP and not lose moneyHow to count money using PHP and not lose money
How to count money using PHP and not lose money
 
New kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingNew kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboarding
 
Time-driven applications
Time-driven applicationsTime-driven applications
Time-driven applications
 
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPJak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
 

Recently uploaded

Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
cpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptcpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptrcbcrtm
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 

Recently uploaded (20)

Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Odoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting ServiceOdoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting Service
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
cpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.pptcpct NetworkING BASICS AND NETWORK TOOL.ppt
cpct NetworkING BASICS AND NETWORK TOOL.ppt
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 

SERIALIZE KILLERS: How we broke our API

  • 1. SERIAL(IZE) KILLERS czyli jak popsuliśmy API Piotr Horzycki / Espeo Software / peterdev.pl
  • 2.
  • 3. PROSTA ENCJA class Product { public function __construct( public readonly string $id, public readonly string $name, public readonly string $price, public readonly string $editedBy, ) { } }
  • 4. SERIALIZE(), CZYLI ZŁO $code = serialize($product); O:7:"Product":4:{s:2:"id";s:3:"123";s:4:"name";s:8:"Chainsaw"; s:5:"price";s:10:"EUR 123.45";s:8:"editedBy";s:4:"John";} $product = unserialize($code);
  • 5. MAŁY PATCH, DUŻY PROBLEM ramsey/uuid 4.2.1 ramsey/uuid 4.2.2 $id = RamseyUuidUuid::uuid4(); C:35:"RamseyUuidLazyLazyUuidFromString":36:{23dc5ed8-4b73-4df8-9421-95e5c07a58e5} O:35:"RamseyUuidLazyLazyUuidFromString":1:{s:6:"string";s:36:"4fdf0133-12be-4089-8fe5-45b4a3e2b
  • 7. KIEDYŚ TO BYŁO... { "example": { "key": "value" } } $request = json_decode(file_get_contents('php://input')); $price = $request['price']; $name = $request['name'] ?? '';
  • 8. KIEDY WYMYŚLONO SERIALIZER $product = new Product('123', 'Chainsaw', 'EUR 123.45', 'John'); $json = $serializer->serialize($product); { "id": "123", "name": "Chainsaw", "price": "EUR 123.45", "editedBy": "John" } $product = $serializer->deserialize($requestBody, Product::class, 'json');
  • 9. KIEDY CHCEMY JESZCZE ORM class Product { public function __construct( #[ORMId, ORMColumn] public readonly string $id, #[ORMColumn] public readonly string $name, #[ORMColumn] public readonly string $price, #[ORMColumn] public readonly string $editedBy, ) { } }
  • 10. KIEDY FRONTEND CHCE COŚ ZMIENIĆ class Product { public function __construct( #[ORMId, ORMColumn] public readonly string $id, #[ORMColumn] #[SerializedName("productName")] public readonly string $name, #[ORMColumn] public readonly string $price, #[ORMColumn] public readonly string $editedBy, ) { } }
  • 11. KIEDY FRONTEND CHCE RÓŻNE DANE class Product { public function __construct( #[ORMId, ORMColumn] #[Groups(['admin', 'cart'])] public readonly string $id, #[ORMColumn] #[Groups(['admin', 'cart'])] #[SerializedName("productName")] public readonly string $name, #[ORMColumn] #[Groups(['cart'])] public readonly string $price, #[ORMColumn] #[Ignore] public readonly string $editedBy, ) { } }
  • 12. KIEDY FRONTEND CHCE COŚ EKSTRA class Product { // ... public function getUniversalAnswer(): int { return 42; } #[Ignore] public function getImportantBusinessLogic(): int { return 2 * 2; } }
  • 13. DORZUCANIE RZECZY POD STOŁEM final class SneakyProductNormalizer implements NormalizerInterface { /** @param Product $object */ public function normalize(mixed $object, string $format = null, array $context = []): ar { return [ 'id' => $object->id, 'name' => $object->name, 'price' => $object->price, 'extraField' => 2 * 2, ]; } // ... }
  • 14. PERFORMANCE 100 pozycji na liście, 301 zapytań SQL...
  • 15. ROZWIĄZANIE: DTO class ProductAdminListDto { public function __construct( public readonly string $id, public readonly string $name, ) { } public static function fromEntity(Product $product): self { return new self($product->id, $product->name); } }
  • 16. OBSŁUGA NULLI I WARTOŚCI NIEZAINICJOWANYCH class Product { public string $sku; public ?string $rating = null; }
  • 17. OBSŁUGA NULLI I WARTOŚCI NIEZAINICJOWANYCH class Product { public string $sku; public ?string $rating = null; } { // "sku" pominięte, chyba że SKIP_UNINITIALIZED_VALUES = false "rating": null // będzie pominięte dla SKIP_NULL_VALUES = true }
  • 18. HISTORIA TRUDNEJ MIGRACJI: JMS -> SYMFONY { "type": "IP", "value": "127.0.0.1", "active": 123 }
  • 19. HISTORIA TRUDNEJ MIGRACJI: JMS -> SYMFONY { "type": "IP", "value": "127.0.0.1", "active": 123 } $rule = $jms->deserialize($requestBody, Rule::class, 'json');
  • 20. HISTORIA TRUDNEJ MIGRACJI: JMS -> SYMFONY { "type": "IP", "value": "127.0.0.1", "active": 123 } $rule = $jms->deserialize($requestBody, Rule::class, 'json'); W PHP mamy active === TRUE...
  • 21. USZCZELNIAMY TYPY, PO CZYM KLIENT ZGŁASZA BŁĄD... Zadanie soft skill: wytłumacz klientowi, że się pomylił { "currency": "GBP", "amount": "1234" // 🔥 }
  • 22. CIĘŻKA PRZEPRAWA Z ENCJAMI inne atrybuty JMS/Symfony gąszcz ExclusionPolicy, Expose, Ignore constructor property promotion, nulle itd.
  • 23. BŁĘDY WALIDACJI TYPÓW W SYMFONY try { $dto = $serializer->deserialize($requestBody, Product::class, 'json', [ DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, ]); } catch (PartialDenormalizationException $e) { $violations = new ConstraintViolationList(); foreach ($e->getErrors() as $exception) { // ... } return $this->json($violations, 400); } https://symfony.com/doc/current/components/serializer.html#collecting-type-errors-while-denormalizing
  • 24. DODANIE NOWEGO POLA, A INTEGRACJA KLIENTA class Notification { public function __construct( public readonly string $paymentId, public readonly string $status, public readonly string $receivedAt, ) { } }
  • 25. DEVELOPERS BE LIKE... "He he... broken... wait a minute..."
  • 26. DODANIE NOWEGO POLA, A INTEGRACJA KLIENTA class NotificationV2 { public function __construct( public readonly string $paymentId, public readonly string $status, public readonly string $receivedAt, public readonly int $version = 2, ) { } }
  • 27. ŹLE NAZWANE POLE OPCJONALNE Walidacja przechodzi, ale funkcjonalność nie działa Rozwiązanie: ALLOW_EXTRA_ATTRIBUTES = false { "currency": "GBP", "amount": 1234, "optionalFieldWithTypo": "foo" // 🔥 }
  • 28.
  • 30. POZIOMY TESTÓW API nie ma żadnych
  • 31. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path)
  • 32. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path) assert HTTP 200 (błędne dane)
  • 33. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path) assert HTTP 200 (błędne dane) assert JSON contains
  • 34. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path) assert HTTP 200 (błędne dane) assert JSON contains assert JSON path equals
  • 35. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path) assert HTTP 200 (błędne dane) assert JSON contains assert JSON path equals assert database contains
  • 36. POZIOMY TESTÓW API nie ma żadnych assert HTTP 200 (happy path) assert HTTP 200 (błędne dane) assert JSON contains assert JSON path equals assert database contains assert no side effects
  • 37. PODZIAŁ ODPOWIEDZIALNOŚCI MIĘDZY WARSTWAMI TESTÓW jednostkowe integracyjne API E2E
  • 38. DOKUMENTACJA? A KOMU TO POTRZEBNE... rozjazd między OpenAPI a implementacją brak przykładów w dokumentacji ciągłe pytania od frontendowców
  • 40. PODSUMOWANIE unikać serialize() nawet drobna różnica w API może popsuć integrację testować API, łącznie z nietypowymi sytuacjami DTO jako pośrednik między encjami a endpointami wersjonowanie lub konfiguracja per klient dokumentacja, która żyje