SlideShare une entreprise Scribd logo
1  sur  72
Télécharger pour lire hors ligne
REST in practice
with Symfony2
@dlondero
OFTEN...
Richardson Maturity Model
NOT
TALKING
ABOUT...
Level 0

POX - RPC
Level 1

RESOURCES
Level 2

HTTP VERBS
Level 3

HYPERMEDIA
TALKING
ABOUT HOW
TO DO
WHAT WE NEED	

!

•symfony/framework-standard-edition	

!

•friendsofsymfony/rest-bundle	

!

•jms/serializer-bundle	

!

•nelmio/api-doc-bundle
//src/Acme/ApiBundle/Entity/Product.php;!

!

use SymfonyComponentValidatorConstraints as Assert;!
use DoctrineORMMapping as ORM;!

!

/**!
* @ORMEntity!
* @ORMTable(name="product")!
*/!
class Product!
{!
/**!
* @ORMColumn(type="integer")!
* @ORMId!
* @ORMGeneratedValue(strategy="AUTO")!
*/!
protected $id;!

!

!

!

/**!
* @ORMColumn(type="string", length=100)!
* @AssertNotBlank()!
*/!
protected $name;!
/**!
* @ORMColumn(type="decimal", scale=2)!
*/!
protected $price;!
/**!
* @ORMColumn(type="text")!
*/!
protected $description;!
CRUD
Create	

HTTP POST
Request
POST /products HTTP/1.1!
Host: acme.com!
Content-Type: application/json!
!

{!
"name": "Product #1",!
"price": 19.90,!
"description": "Awesome product"!
}!
Response
HTTP/1.1 201 Created!
Location: http://acme.com/products/1!
Content-Type: application/json!
!

{!
"product": {!
"id": 1,!
"name": "Product #1",!
"price": 19.9,!
"description": "Awesome product"!
}!
//src/Acme/ApiBundle/Resources/config/routing.yml!
!
acme_api_product_post:!
pattern: /products!
defaults: { _controller: AcmeApiBundle:ApiProduct:post,
_format: json }!
requirements:!
_method: POST
//src/Acme/ApiBundle/Controller/ApiProductController.php!

!

use FOSRestBundleViewView;!

!

public function postAction(Request $request)!
{!
$product = $this->deserialize(!
'AcmeApiBundleEntityProduct',!
$request!
);!

!
!
!

!
!

if ($product instanceof Product === false) {!
return View::create(array('errors' => $product), 400);!
}!
$em = $this->getEM();!
$em->persist($product);!
$em->flush();!
$url = $this->generateUrl(!
'acme_api_product_get_single',!
array('id' => $product->getId()),!
true!
);!
$response = new Response();!
$response->setStatusCode(201);!
$response->headers->set('Location', $url);!
return $response;!

}
Read	

HTTP GET
Request
GET /products/1 HTTP/1.1!
Host: acme.com
Response
HTTP/1.1 200 OK!
Content-Type: application/json!
!

{!
"product": {!
"id": 1,!
"name": "Product #1",!
"price": 19.9,!
"description": "Awesome product"!
}!
public function getSingleAction(Product $product)!
{!
return array('product' => $product);!
}
Update	

HTTP PUT
Request
PUT /products/1 HTTP/1.1!
Host: acme.com!
Content-Type: application/json!
!

{!
"name": "Product #1",!
"price": 29.90,!
"description": "Awesome product"!
}!
Response
HTTP/1.1 204 No Content!
!

HTTP/1.1 200 OK!
Content-Type: application/json!
!

{!
"product": {!
"id": 1,!
"name": "Product #1",!
"price": 29.90,!
"description": "Awesome product"!
}!
//src/Acme/ApiBundle/Controller/ApiProductController.php!

!
use FOSRestBundleControllerAnnotationsView as RestView;!

!
/**!
* @RestView(statusCode=204)!
*/!
public function putAction(Product $product, Request $request)!
{!
$newProduct = $this->deserialize(!
'AcmeApiBundleEntityProduct',!
$request!
);!

!
if ($newProduct instanceof Product === false) {!
return View::create(array('errors' => $newProduct), 400);!
}!

!
$product->merge($newProduct);!

!
$this->getEM()->flush();!
}
Partial Update	

HTTP PATCH
Request
PATCH /products/1 HTTP/1.1!
Host: acme.com!
Content-Type: application/json!
!

{!
"price": 39.90,!
}!
Response
HTTP/1.1 204 No Content!
!

HTTP/1.1 200 OK!
Content-Type: application/json!
!

{!
"product": {!
"id": 1,!
"name": "Product #1",!
"price": 39.90,!
"description": "Awesome product"!
}!
//src/Acme/ApiBundle/Controller/ApiProductController.php!

!
use FOSRestBundleControllerAnnotationsView as RestView;!

!
/**!
* @RestView(statusCode=204)!
*/!
public function patchAction(Product $product, Request $request)!
{!
$validator = $this->get('validator');!

!
$raw = json_decode($request->getContent(), true);!

!
$product->patch($raw);!

!
if (count($errors = $validator->validate($product))) {!
return $errors;!
}!

!
$this->getEM()->flush();!
}
Delete	

HTTP DELETE
Request
DELETE /products/1 HTTP/1.1!
Host: acme.com
Response

HTTP/1.1 204 No Content
//src/Acme/ApiBundle/Controller/ApiProductController.php!

!
use FOSRestBundleControllerAnnotationsView as RestView;!

!
/**!
* @RestView(statusCode=204)!
*/!
public function deleteAction(Product $product)!
{!
$em = $this->getEM();!
$em->remove($product);!
$em->flush();!
}
Serialization
use JMSSerializerAnnotation as Serializer;!

!

/**!
* @SerializerExclusionPolicy("all")!
*/!
class Product!
{!
/**!
* @SerializerExpose!
* @SerializerType("integer")!
*/!
protected $id;!

!

!

!

/**!
* @SerializerExpose!
* @SerializerType("string")!
*/!
protected $name;!
/**!
* @SerializerExpose!
* @SerializerType("double")!
*/!
protected $price;!
/**!
* @SerializerExpose!
* @SerializerType("string")!
*/!
protected $description;!
Deserialization
//src/Acme/ApiBundle/Controller/ApiController.php!

!
protected function deserialize($class, Request $request, $format = 'json')!
{!
$serializer = $this->get('serializer');!
$validator = $this->get('validator');!

!
try {!
$entity = $serializer->deserialize(!
$request->getContent(),!
$class,!
$format!
);!
} catch (RuntimeException $e) {!
throw new HttpException(400, $e->getMessage());!
}!

!
if (count($errors = $validator->validate($entity))) {!
return $errors;!
}!

!
return $entity;!
}!
Testing
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!

use LiipFunctionalTestBundleTestWebTestCase;!

!

class ApiProductControllerTest extends WebTestCase!
{!
public function testPost()!
{!
$this->loadFixtures(array());!

!

$product = array(!
'name' => 'Product #1',!
'price' => 19.90,!
'description' => 'Awesome product',!
);!

!

$client = static::createClient();!
$client->request(!
'POST', !
'/products', !
array(), array(), array(), !
json_encode($product)!
);!

!

$this->assertEquals(201, $client->getResponse()->getStatusCode());!
$this->assertTrue($client->getResponse()->headers->has('Location'));!
$this->assertContains(!
"/products/1", !
$client->getResponse()->headers->get('Location')!
);!
}!
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testPostValidation()!
{!
$this->loadFixtures(array());!

!
$product = array(!
'name' => '',!
'price' => 19.90,!
'description' => 'Awesome product',!
);!

!
$client = static::createClient();!
$client->request(!
'POST', !
'/products', !
array(), array(), array(), !
json_encode($product)!
);!

!
$this->assertEquals(400, $client->getResponse()->getStatusCode());!
}!
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testGetAction()!
{!
$this->loadFixtures(array(!
'AcmeApiBundleTestsFixturesProduct',!
));!

!
$client = static::createClient();!
$client->request('GET', '/products');!

!
$this->isSuccessful($client->getResponse());!
$response = json_decode($client->getResponse()->getContent());!

!
$this->assertTrue(isset($response->products));!
$this->assertCount(1, $response->products);!

!
$product = $response->products[0];!
$this->assertSame('Product #1', $product->name);!
$this->assertSame(19.90, $product->price);!
$this->assertSame('Awesome product!', $product->description);!
}
//src/Acme/ApiBundle/Tests/Fixtures/Product.php!

!
use AcmeApiBundleEntityProduct as ProductEntity;!

!
use DoctrineCommonPersistenceObjectManager;!
use DoctrineCommonDataFixturesFixtureInterface;!

!
class Product implements FixtureInterface!
{!
public function load(ObjectManager $em)!
{!
$product = new ProductEntity();!
$product->setName('Product #1');!
$product->setPrice(19.90);!
$product->setDescription('Awesome product!');!

!
$em->persist($product);!
$em->flush();!
}!
}!
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testGetSingleAction()!
{!
$this->loadFixtures(array(!
'AcmeApiBundleTestsFixturesProduct',!
));!

!
$client = static::createClient();!
$client->request('GET', '/products/1');!

!
$this->isSuccessful($client->getResponse());!
$response = json_decode($client->getResponse()->getContent());!

!
$this->assertTrue(isset($response->product));!
$this->assertEquals(1, $response->product->id);!
$this->assertSame('Product #1', $response->product->name);!
$this->assertSame(19.90, $response->product->price);!
$this->assertSame(!
'Awesome product!', !
$response->product->description!
);!
}
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testPutAction()!
{!
$this->loadFixtures(array(!
'AcmeApiBundleTestsFixturesProduct',!
));!

!
$product = array(!
'name' => 'New name',!
'price' => 39.90,!
'description' => 'Awesome new description'!
);!

!
$client = static::createClient();!
$client->request(!
'PUT', !
'/products/1', !
array(), array(), array(), !
json_encode($product)!
);!

!
$this->isSuccessful($client->getResponse());!
$this->assertEquals(204, $client->getResponse()->getStatusCode());!
}
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
/**!
* @depends testPutAction!
*/!
public function testPutActionWithVerification()!
{!
$client = static::createClient();!
$client->request('GET', '/products/1');!
$this->isSuccessful($client->getResponse());!
$response = json_decode($client->getResponse()->getContent());!

!
$this->assertTrue(isset($response->product));!
$this->assertEquals(1, $response->product->id);!
$this->assertSame('New name', $response->product->name);!
$this->assertSame(39.90, $response->product->price);!
$this->assertSame(!
'Awesome new description', !
$response->product->description!
);!
}
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testPatchAction()!
{!
$this->loadFixtures(array(!
'AcmeApiBundleTestsFixturesProduct',!
));!

!
$patch = array(!
'price' => 29.90!
);!

!
$client = static::createClient();!
$client->request(!
'PATCH', !
'/products/1', !
array(), array(), array(), !
json_encode($patch)!
);!
!
$this->isSuccessful($client->getResponse());!
$this->assertEquals(204, $client->getResponse()->getStatusCode());!
}
//src/Acme/ApiBundle/Tests/Controller/ApiProductControllerTest.php!

!
public function testDeleteAction()!
{!
$this->loadFixtures(array(!
'AcmeApiBundleTestsFixturesProduct',!
));!

!
$client = static::createClient();!
$client->request('DELETE', '/products/1');!
$this->assertEquals(204, $client->getResponse()->getStatusCode());!
}
Documentation
//src/Acme/ApiBundle/Controller/ApiProductController.php!

!

use NelmioApiDocBundleAnnotationApiDoc;!

!

/**!
* Returns representation of a given product!
*!
* **Response Format**!
*!
*
{!
*
"product": {!
*
"id": 1,!
*
"name": "Product #1",!
*
"price": 19.9,!
*
"description": "Awesome product"!
*
}!
*
}!
*!
* @ApiDoc(!
*
section="Products",!
*
statusCodes={!
*
200="OK",!
*
404="Not Found"!
*
}!
* )!
*/!
public function getSingleAction(Product $product)!
{!
return array('product' => $product);!
}!
Hypermedia?
There’s a bundle
for that™
willdurand/hateoas-bundle
fsc/hateoas-bundle
//src/Acme/ApiBundle/Entity/Product.php;!

!
use JMSSerializerAnnotation as Serializer;!
use FSCHateoasBundleAnnotation as Rest;!
use DoctrineORMMapping as ORM;!

!
/**!
* @ORMEntity!
* @ORMTable(name="product")!
* @SerializerExclusionPolicy("all")!
* @RestRelation(!
*
"self", !
*
href = @RestRoute("acme_api_product_get_single", !
*
parameters = { "id" = ".id" })!
* )!
* @RestRelation(!
*
"products", !
*
href = @RestRoute("acme_api_product_get")!
* )!
*/!
class Product!
{!
...!
}
application/hal+json
GET /orders/523 HTTP/1.1!
Host: example.org!
Accept: application/hal+json!
!

HTTP/1.1 200 OK!
Content-Type: application/hal+json!
!

{!
"_links": {!
"self": { "href": "/orders/523" },!
"invoice": { "href": "/invoices/873" }!
},!
"currency": "USD",!
"total": 10.20!
}
“What needs to be done to make the REST
architectural style clear on the notion that
hypertext is a constraint? In other words, if the
engine of application state (and hence the API)
is not being driven by hypertext, then it cannot
be RESTful and cannot be a REST API. Period.
Is there some broken manual somewhere that
needs to be fixed?”
Roy Fielding
“Anyway, being pragmatic, sometimes a level
2 well done guarantees a good API…”
Daniel Londero
“But don’t call it RESTful. Period.”
Roy Fielding
“Ok.”
Daniel Londero
THANKS
@dlondero

Contenu connexe

Tendances

Tendances (20)

Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
 
Javascript laravel's friend
Javascript laravel's friendJavascript laravel's friend
Javascript laravel's friend
 
PhpSpec extension points
PhpSpec extension pointsPhpSpec extension points
PhpSpec extension points
 
Web service with Laravel
Web service with LaravelWeb service with Laravel
Web service with Laravel
 
REST API Laravel
REST API LaravelREST API Laravel
REST API Laravel
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Sf2 wtf
Sf2 wtfSf2 wtf
Sf2 wtf
 
Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5
 
Building Modern and Secure PHP Applications – Codementor Office Hours with Be...
Building Modern and Secure PHP Applications – Codementor Office Hours with Be...Building Modern and Secure PHP Applications – Codementor Office Hours with Be...
Building Modern and Secure PHP Applications – Codementor Office Hours with Be...
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
The new features of PHP 7
The new features of PHP 7The new features of PHP 7
The new features of PHP 7
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
 
Rails web api 开发
Rails web api 开发Rails web api 开发
Rails web api 开发
 
Zend framework
Zend frameworkZend framework
Zend framework
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à Ruby
 
Silex, the microframework
Silex, the microframeworkSilex, the microframework
Silex, the microframework
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
How to driver your webservices with ansible
How to driver your webservices with ansibleHow to driver your webservices with ansible
How to driver your webservices with ansible
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
 
Symfony2, Backbone.js & socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js & socket.io - SfLive Paris 2k13 - WisemblySymfony2, Backbone.js & socket.io - SfLive Paris 2k13 - Wisembly
Symfony2, Backbone.js & socket.io - SfLive Paris 2k13 - Wisembly
 

Similaire à REST in practice with Symfony2

Similaire à REST in practice with Symfony2 (20)

Rest in practice con Symfony2
Rest in practice con Symfony2Rest in practice con Symfony2
Rest in practice con Symfony2
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Es.next
Es.nextEs.next
Es.next
 
OSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with GoOSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with Go
 
Swift - the future of iOS app development
Swift - the future of iOS app developmentSwift - the future of iOS app development
Swift - the future of iOS app development
 
Moving to modules
Moving to modulesMoving to modules
Moving to modules
 
From CakePHP to Laravel
From CakePHP to LaravelFrom CakePHP to Laravel
From CakePHP to Laravel
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Getting Into FLOW3 (DPC12)
Getting Into FLOW3 (DPC12)Getting Into FLOW3 (DPC12)
Getting Into FLOW3 (DPC12)
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
api-platform: the ultimate API platform
api-platform: the ultimate API platformapi-platform: the ultimate API platform
api-platform: the ultimate API platform
 
Symfony CMF - PHP Conference Brazil 2011
Symfony CMF - PHP Conference Brazil 2011Symfony CMF - PHP Conference Brazil 2011
Symfony CMF - PHP Conference Brazil 2011
 
TYPO3 Flow 2.0 Workshop T3BOARD13
TYPO3 Flow 2.0 Workshop T3BOARD13TYPO3 Flow 2.0 Workshop T3BOARD13
TYPO3 Flow 2.0 Workshop T3BOARD13
 
InspiringCon15: Bringing TYPO3 Legacy Applications into the Flow
InspiringCon15: Bringing TYPO3 Legacy Applications into the FlowInspiringCon15: Bringing TYPO3 Legacy Applications into the Flow
InspiringCon15: Bringing TYPO3 Legacy Applications into the Flow
 
IPCSE12: Hands on FLOW3
IPCSE12: Hands on FLOW3IPCSE12: Hands on FLOW3
IPCSE12: Hands on FLOW3
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
 
IPCSE12: Getting into FLOW3
IPCSE12: Getting into FLOW3IPCSE12: Getting into FLOW3
IPCSE12: Getting into FLOW3
 
Hacking 101 for developers
Hacking 101 for developersHacking 101 for developers
Hacking 101 for developers
 

Plus de Daniel Londero

Symfony e grandi numeri: si può fare!
Symfony e grandi numeri: si può fare!Symfony e grandi numeri: si può fare!
Symfony e grandi numeri: si può fare!
Daniel Londero
 

Plus de Daniel Londero (9)

Magento meets vagrant
Magento meets vagrantMagento meets vagrant
Magento meets vagrant
 
Random Tips for Remote Working
Random Tips for Remote WorkingRandom Tips for Remote Working
Random Tips for Remote Working
 
Lavorare da casa: siamo pronti?
Lavorare da casa: siamo pronti?Lavorare da casa: siamo pronti?
Lavorare da casa: siamo pronti?
 
Symfony2, SQL e NoSQL. Assieme. Si può.
Symfony2, SQL e NoSQL. Assieme. Si può.Symfony2, SQL e NoSQL. Assieme. Si può.
Symfony2, SQL e NoSQL. Assieme. Si può.
 
Lavorare da casa: siamo pronti?
Lavorare da casa: siamo pronti?Lavorare da casa: siamo pronti?
Lavorare da casa: siamo pronti?
 
Io cache, tu database
Io cache, tu databaseIo cache, tu database
Io cache, tu database
 
Unit testing 101
Unit testing 101Unit testing 101
Unit testing 101
 
Symfony e grandi numeri: si può fare!
Symfony e grandi numeri: si può fare!Symfony e grandi numeri: si può fare!
Symfony e grandi numeri: si può fare!
 
Enterprise Open Source: Il caso PHP
Enterprise Open Source: Il caso PHPEnterprise Open Source: Il caso PHP
Enterprise Open Source: Il caso PHP
 

Dernier

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Dernier (20)

Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 

REST in practice with Symfony2