SlideShare a Scribd company logo
1 of 54
Download to read offline
Agile Web Development
Liip.ch
–
RESTING WITH
Learn how to use and extend the OroCRM REST API
AGENDA
• Introduction to REST theory
• How to discover OroCRM Rest APIs
• How to use OroCRM REST APIs
• How to add a new REST APIs to OroCRM
INTRODUCTION TO REST
Everyone who has ever talked
about REST, at some point has said
something idiotic about REST.
Except for maybe Roy Fielding.
For example, I once thought it
meant converting all GET
parameters to virtual directories.
Differentiating GET and POST
seemed like overzealous
academics.
I only began to understand why
REST really makes sense and what
REST it is really about when I
started looking into cache headers
and reverse proxies.
REST is all about leveraging HTTP
and constraining your application
to a set of rules, so that users of
your API can safely apply
assumptions about the behavior of
your application.
HTTP Request Anatomy
GET /notes HTTP/1.1
Host: symfony-rest-edition.lo
Accept: application/json;q=0.9,*/*;q=0.8
Content-Type: application/json
Content-Length: length
HTTP Response Anatomy
HTTP/1.1 200 OK
Allow: GET, POST
Cache-Control: max-age=15, public, s-maxage=30
Content-Type: application/json
Date: Wed, 15 Jan 2014 15:09:01 GMT
Last-Modified: Wed, 15 Jan 2014 14:09:03 GMT
Server: Apache/2.2.24 (Unix) DAV/2 PHP/5.4.20 mod_ssl/
2.2.24 OpenSSL/0.9.8y
Vary: Accept-Encoding,Accept-Language
{"notes":["a","b","c"]}
REST MATURITY MODEL
http://martinfowler.com/articles/richardsonMaturityModel.html
RMM LEVEL 0
• Aka "The Swamp of POX"
• HTTP as a tunneling mechanism
• "Procedural" communication (RPC)
• Single endpoint (per operation)
RMM LEVEL 0
http://martinfowler.com/articles/richardsonMaturityModel.html
RMM LEVEL 1
• Aka "Resources"
• Individual resources, i.e. URIs
• "Object orientated" communication
RMM LEVEL 1
http://martinfowler.com/articles/richardsonMaturityModel.html
RMM LEVEL 2
• Aka "HTTP Verbs"
• Client uses specific HTTP method
• Server uses HTTP status codes
RMM LEVEL 2
http://martinfowler.com/articles/richardsonMaturityModel.html
HTTP VERBS
Method Safe Idempotent
GET yes yes
HEAD yes yes
POST no no
PUT no yes
DELETE no yes (*)
.. no no
SAFE VS. IDEMPOTENT
• Safe means cacheable
• Idempotent means result independent of the # of executions, but..
• Does this apply to server state or also to the HTTP response?
• Is DELETE idempotent or not, ie. what should be the response
for a DELETE requests on a non existent resource? 404 or 200?
HTTP STATUS CODES
Code range Description Example
1xx Information 100 - Continue
2xx Successful 201 - Created
3xx Redirection 301 - Moved
Permanently
4xx Client Error 404 - Not Found
5xx Server Error 501 - Not
Implemented
RMM LEVEL 3
• Aka "Hypermedia Control"
• Service discovery via link relations
• ATOM, HAL, JSON-LD, IANA Link Rel
RMM LEVEL 3
http://martinfowler.com/articles/richardsonMaturityModel.html
HYPERTEXT AS THE ENGINE OF
APPLICATION STATE
=
HATEOAS
RMM VS REST VS REAL LIFE
• Most developers consider RMM Level 2 sufficient for REST
• RMM Level 3 is a precondition but not sufficient for REST
• ie. RMM only covers a subset of what REST requires
• RMM Level 3 makes URI forma ing ma er less
RMM VS REST VS REAL LIFE
• Browsers are bad REST clients
• REST is protocol independent
• Few (no?) clients really leverage HATEOAS
CONTENT TYPE NEGOTIATION
UNIFIED RESOURCE IDENTIFIER
• URIs identify resources
• URIs are format independent
• URI "file extensions" != RESTful
MEDIA TYPES
• Identifies a representation format
• Custom types use application/vnd.[XYZ]
• Used inside the Accept / Content-Type headers
Header Description
Content-Type HTTP message format
Accept HTTP response format preference
• Finding appropriate response format
• No standardized algorithm available
• Apache mod_negotiation algorithm is documented
• Also covers encoding (Accept-Encoding) and language (Accept-
Language) negotiation
CONTENT TYPE NEGOTIATION
EXAMPLE
Accept: application/json, application/xml;q=0.9, text/
html;q=0.8, text/*;q=0.7, */*;q=0.5
Priority Description
q=1.0 application/json
q=0.9 application/xml
q=0.8 text/html
q=0.7 text/* (ie. any text)
q=0.5 */* (ie. any media type)
OUT OF THE BOX OROCRM REST APIS
• $> app/console router:debug | grep api
• API Docs via NelmioApiDocBundle, ie. “/api/doc/“
• Enduser friendly API overview
• Includes a sandbox to try out API calls
• Information is extracted from Annotations on the Controllers
USING OROCRM REST APIS
• Constructing the URL for: api/rest/{version}/accounts/{id}.{_format}
• Symfony uses a syntax based on RFC 6570 for templated URI
• {version} = “v1” (recommended) or “latest”
• {id} = ID of an Account instance
• {_format} = lazy content type negotiation, ie. “.json”, or use HTTP header
“Accept: application/json”
http://httpie.org/
HTTPie (pronounced
aych-tee-tee-pie) is a
command line HTTP
client. Its goal is to
make CLI interaction
with web services as
human-friendly as
possible. It provides a
simple “http” command
that allows for sending
arbitrary HTTP requests
using a simple and
natural syntax, and
displays colorized
output. HTTPie can be
used for testing,
debugging, and
generally interacting
with HTTP servers.
WSSE SECURITY
$> http --json http://orocrm.lo/api/rest/v1/accounts
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Content-Type: application/json
Date: Wed, 22 Jul 2015 12:09:08 GMT
Server: Apache/2.4.10 (Unix) PHP/5.6.9
Set-Cookie: CRMID=i45n7g8phauhrfr2h53fh576q1; path=/;
HttpOnly
Transfer-Encoding: chunked
WWW-Authenticate: WSSE realm="Secured API",
profile="UsernameToken"
GENERATING THE WSSE HEADER
$> app/console oro:wsse:generate-header
c51ef6cb3e87dcc6f077b93f0ceb778d23669364
To use WSSE authentication add following headers to the
request:
Authorization: WSSE profile="UsernameToken"
X-WSSE: UsernameToken Username="admin",
PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=",
Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==",
Created=“2015-07-22T14:12:27+02:00"
http://www.orocrm.com/documentation/index/current/cookbook/how-to-use-wsse-authentication
READING OROCRM REST APIS
$> http --json http://orocrm.lo/api/rest/v1/accounts
'X-WSSE: UsernameToken Username="admin",
PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=",
Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==",
Created=“2015-07-22T14:12:27+02:00"'
[
{
"contacts": {},
"createdAt": "2015-07-06T09:12:31+00:00",
"defaultContact": "Mr. Jerry Coleman",
"id": 1,
"name": "Life Plan Counselling",
"organization": "Liip Test",
WRITING TO OROCRM REST APIS
$> http POST --json http://orocrm.lo/api/rest/v1/accounts/1
'X-WSSE: UsernameToken Username="admin",
PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=",
Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==",
Created=“2015-07-22T14:12:27+02:00"' < account.json
$> cat account.json
{
"account": {
"owner": 2
}
}
DEMO TIME
APPROACHES TO CREATE A NEW API
• OroCRM has uses various different approaches
• Long term goal of OroCRM is to provide SOAP and REST via the same code
• Available approaches:
• Helper methods in Oro Platform RestGetController
• Serialization via JMS Serializer or via Symfony core Serializer
• Oro Platform EntitySerializer is a work in progress which make it even
easier to cover REST and SOAP with the same controller
BASIC CONTROLLER SETUP
<?php



namespace AcmeBundleCartBundleControllerApiRest;



use FOSRestBundleControllerAnnotationsNamePrefix;

use FOSRestBundleRoutingClassResourceInterface;

use OroBundleSoapBundleControllerApiRestRestController;



/**

* @NamePrefix("acme_api_")

*/

class CartController extends RestController implements ClassResourceInterface

{

..
}
IMPLEMENTING GETTING A LIST (1/3)
/**

* REST GET list

*

* @ApiDoc(

* description="Get all carts",

* resource=true

* )

* @AclAncestor("orocrm_magento_cart_view")

*

* @return JsonResponse

*/

public function cgetAction()

{

/** @var Cart[] $carts */

$carts = $this->getManager()->getListQueryBuilder()->getQuery()->execute();



return new JsonResponse(

$this->getPreparedItems($carts, self::$fields),

Codes::HTTP_OK

);

}
IMPLEMENTING GETTING A LIST (2/3)
<?php



namespace AcmeBundleCartBundleControllerApiRest;

use OroCRMBundleMagentoBundleEntityCart;



use SymfonyComponentHttpFoundationJsonResponse;

use FOSRestBundleControllerAnnotationsNamePrefix;

use FOSRestBundleRoutingClassResourceInterface;

use FOSRestBundleUtilCodes;

use NelmioApiDocBundleAnnotationApiDoc;



use OroBundleSecurityBundleAnnotationAclAncestor;

use OroBundleSoapBundleControllerApiRestRestController;
class CartController extends RestController implements ClassResourceInterface

{
static $fields = array('id', 'subTotal', 'grandTotal', 'taxAmount', 'customer')
..

}
IMPLEMENTING GETTING A LIST (3/3)
/**

* {@inheritdoc}

*/

public function getManager()

{

return $this->get('acme.cart.manager.api');

}



/**

* Prepare entity field for serialization

*

* @param string $field

* @param mixed $value

*/

protected function transformEntityField($field, &$value)

{

if ($value instanceof Customer) {

$value = array('name' => $value->getLastName());

return;

}

parent::transformEntityField($field, $value);

}
IMPLEMENTING GETTING A ONE ENTITY
/**

* REST GET one

*

* @ApiDoc(

* description="Get one cart",

* resource=true

* )

* @AclAncestor("orocrm_magento_cart_view")

* @param int $cartId

*

* @return JsonResponse

*/

public function getAction($cartId)

{

/** @var Cart $cart */

$cart = $this->getManager()->find($cartId);



return new JsonResponse(

$this->getPreparedItem($cart, self::$fields),

empty($cartId) ? Codes::HTTP_NOT_FOUND : Codes::HTTP_OK

);

}
FULL EXAMPLE
<?php



namespace OroCRMBundleMagentoBundleControllerApiRest;



use OroCRMBundleMagentoBundleEntityCustomer;

use OroCRMBundleMagentoBundleEntityCart;



use SymfonyComponentHttpFoundationJsonResponse;



use FOSRestBundleControllerAnnotationsNamePrefix;

use FOSRestBundleRoutingClassResourceInterface;

use FOSRestBundleUtilCodes;



use NelmioApiDocBundleAnnotationApiDoc;



use OroBundleSecurityBundleAnnotationAclAncestor;

use OroBundleSoapBundleControllerApiRestRestController;



/**

* @NamePrefix("acme_api_")

*/

class CartController extends RestController implements ClassResourceInterface

{

static $fields = array('id', 'subTotal', 'grandTotal', 'taxAmount', 'customer');



/**

* REST GET list

*

* @ApiDoc(

* description="Get all carts",

* resource=true

* )

* @AclAncestor("orocrm_magento_cart_view")

*

* @return JsonResponse

*/

public function cgetAction()

{

/** @var Cart[] $carts */

$carts = $this->getManager()->getListQueryBuilder()->getQuery()->execute();



return new JsonResponse(

$this->getPreparedItems($carts, self::$fields),

Codes::HTTP_OK

);

}

/**

* REST GET one

*

* @ApiDoc(

* description="Get one cart",

* resource=true

* )

* @AclAncestor("orocrm_magento_cart_view")

* @param int $cartId

*

* @return JsonResponse

*/

public function getAction($cartId)

{

/** @var Cart $cart */

$cart = $this->getManager()->find($cartId);



return new JsonResponse(

$this->getPreparedItem($cart, self::$fields),

empty($cartId) ? Codes::HTTP_NOT_FOUND : Codes::HTTP_OK

);

}



public function getManager()

{

return $this->get('orocrm_magento.cart.manager.api');

}



protected function transformEntityField($field, &$value)

{

if ($value instanceof Customer) {

$value = array('name' => $value->getLastName());

return;

}

parent::transformEntityField($field, $value);

}



public function getFormHandler()

{

throw new BadMethodCallException('FormHandler is not available.');

}

}

REQUIRED SERVICE
# services.yml
parameters:
acme.cart.manager.api.class: OroBundleSoapBundle..ApiEntityManager

services:
acme.cart.manager.api:

class: %acme.cart.manager.api.class%

parent: oro_soap.manager.entity_manager.abstract

arguments:

- %orocrm_magento.entity.cart.class%

- @doctrine.orm.entity_manager
REQUIRED ROUTE DEFINITION
# routing.yml
acme_bundle_cart_api:

resource: "@AcmeCartBundle/Controller/Api/Rest/CartController.php"

type: rest

prefix: api/rest/{version}

requirements:

version: latest|v1

defaults:

version: latest
USING OUR NEW OROCRM REST API
$> http --json http://orocrm.lo/api/rest/v1/carts ‘X-WSSE..’
..
[
{
"customer": {
"name": "Clark"
},
"grandTotal": "163.9248",
"id": 1,
"subTotal": "163.9248",
"taxAmount": "12.6748"
},
TESTING OROCRM REST APIS (1/2)
use OroBundleTestFrameworkBundleTestWebTestCase;



class ApiCartControllerTest extends WebTestCase

{

/* Taken from BazingaRestExtraBundle */

protected function assertJsonResponse($response, $statusCode = 200)

{

$this->assertEquals(

$statusCode, $response->getStatusCode(),

$response->getContent()

);

$this->assertTrue(

$response->headers->contains('Content-Type', 'application/json'),

$response->headers

);

}



protected function setUp()

{

$this->initClient(array(), $this->generateWsseAuthHeader());

}
..

TESTING OROCRM REST APIS (2/2)
public function testGetCarts()

{

$this->client->request('HEAD', '/api/rest/v1/carts');

$response = $this->client->getResponse();

$this->assertEquals(200, $response->getStatusCode(), $response->getContent());



$this->client->request('GET', ‘/api/rest/v1/carts');

$response = $this->client->getResponse();



$this->assertJsonResponse($response);

$this->assertEquals(‘..’, $response->getContent());

}



public function testGetCart()

{

$this->client->request('GET', '/api/rest/v1/carts/1');

$response = $this->client->getResponse();



$this->assertJsonResponse($response);

$this->assertEquals('{"id":
1,"subTotal":"163.9248","grandTotal":"163.9248","taxAmount":"12.6748","customer":
{"name":"Clark"}}', $response->getContent());

}
DEMO TIME
Agile Web Development
Liip.ch
–
QUESTIONS?
THANK YOU VERY MUCH!

More Related Content

What's hot

Java rmi example program with code
Java rmi example program with codeJava rmi example program with code
Java rmi example program with code
kamal kotecha
 

What's hot (19)

Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play Framework
 
Maven
MavenMaven
Maven
 
Spring core
Spring coreSpring core
Spring core
 
Wt unit 3
Wt unit 3 Wt unit 3
Wt unit 3
 
This is how we REST
This is how we RESTThis is how we REST
This is how we REST
 
Build restful ap is with python and flask
Build restful ap is with python and flaskBuild restful ap is with python and flask
Build restful ap is with python and flask
 
Wt unit 4
Wt unit 4Wt unit 4
Wt unit 4
 
ExtJs Basic Part-1
ExtJs Basic Part-1ExtJs Basic Part-1
ExtJs Basic Part-1
 
RESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher PecoraroRESTful API development in Laravel 4 - Christopher Pecoraro
RESTful API development in Laravel 4 - Christopher Pecoraro
 
Java rmi example program with code
Java rmi example program with codeJava rmi example program with code
Java rmi example program with code
 
Laravel 5
Laravel 5Laravel 5
Laravel 5
 
.NET Core, ASP.NET Core Course, Session 6
.NET Core, ASP.NET Core Course, Session 6.NET Core, ASP.NET Core Course, Session 6
.NET Core, ASP.NET Core Course, Session 6
 
Web service with Laravel
Web service with LaravelWeb service with Laravel
Web service with Laravel
 
Web services with laravel
Web services with laravelWeb services with laravel
Web services with laravel
 
Cfml features modern_coding
Cfml features modern_codingCfml features modern_coding
Cfml features modern_coding
 
JavaFX Enterprise (JavaOne 2014)
JavaFX Enterprise (JavaOne 2014)JavaFX Enterprise (JavaOne 2014)
JavaFX Enterprise (JavaOne 2014)
 
Red5 - PHUG Workshops
Red5 - PHUG WorkshopsRed5 - PHUG Workshops
Red5 - PHUG Workshops
 
REST API Best Practices & Implementing in Codeigniter
REST API Best Practices & Implementing in CodeigniterREST API Best Practices & Implementing in Codeigniter
REST API Best Practices & Implementing in Codeigniter
 
Servlets
ServletsServlets
Servlets
 

Viewers also liked

Integration with presta shop webinar
Integration with presta shop webinarIntegration with presta shop webinar
Integration with presta shop webinar
Oro Inc.
 
Benefits of Magento + OroCRM Webinar
Benefits of Magento + OroCRM WebinarBenefits of Magento + OroCRM Webinar
Benefits of Magento + OroCRM Webinar
Oro Inc.
 

Viewers also liked (12)

Oro Meetup London - Allies: How can we really turn data into profit?
Oro Meetup London - Allies: How can we really turn data into profit?Oro Meetup London - Allies: How can we really turn data into profit?
Oro Meetup London - Allies: How can we really turn data into profit?
 
B2B, soyez prêts pour la 2ème vague e-commerce - Akeneo, Oro MeetUp, Paris
B2B, soyez prêts pour la 2ème vague e-commerce - Akeneo, Oro MeetUp, ParisB2B, soyez prêts pour la 2ème vague e-commerce - Akeneo, Oro MeetUp, Paris
B2B, soyez prêts pour la 2ème vague e-commerce - Akeneo, Oro MeetUp, Paris
 
Integration with presta shop webinar
Integration with presta shop webinarIntegration with presta shop webinar
Integration with presta shop webinar
 
Comment April Moto met en place une relation client multicanal et augmente so...
Comment April Moto met en place une relation client multicanal et augmente so...Comment April Moto met en place une relation client multicanal et augmente so...
Comment April Moto met en place une relation client multicanal et augmente so...
 
"New OroCRM Release Demo: Discover what’s new in the latest release of OroCRM...
"New OroCRM Release Demo: Discover what’s new in the latest release of OroCRM..."New OroCRM Release Demo: Discover what’s new in the latest release of OroCRM...
"New OroCRM Release Demo: Discover what’s new in the latest release of OroCRM...
 
Benefits of Magento + OroCRM Webinar
Benefits of Magento + OroCRM WebinarBenefits of Magento + OroCRM Webinar
Benefits of Magento + OroCRM Webinar
 
OroCRM - Symfony MeetUp
OroCRM - Symfony MeetUpOroCRM - Symfony MeetUp
OroCRM - Symfony MeetUp
 
Oro Meetup in London - Oro product vision
Oro Meetup in London - Oro product visionOro Meetup in London - Oro product vision
Oro Meetup in London - Oro product vision
 
Email is the digital key - dotmailer, Oro MeetUp, Paris
Email is the digital key - dotmailer, Oro MeetUp, ParisEmail is the digital key - dotmailer, Oro MeetUp, Paris
Email is the digital key - dotmailer, Oro MeetUp, Paris
 
Benefits of OroCRM + Magento Webinar
Benefits of OroCRM + Magento WebinarBenefits of OroCRM + Magento Webinar
Benefits of OroCRM + Magento Webinar
 
Powerful Customer Service with OroCRM + Zendesk
Powerful Customer Service with OroCRM + ZendeskPowerful Customer Service with OroCRM + Zendesk
Powerful Customer Service with OroCRM + Zendesk
 
How to Close More Deals with B2B eCommerce Systems
How to Close More Deals with B2B eCommerce SystemsHow to Close More Deals with B2B eCommerce Systems
How to Close More Deals with B2B eCommerce Systems
 

Similar to Resting with OroCRM Webinar

REST API Recommendations
REST API RecommendationsREST API Recommendations
REST API Recommendations
Jeelani Shaik
 

Similar to Resting with OroCRM Webinar (20)

ASP.NET Mvc 4 web api
ASP.NET Mvc 4 web apiASP.NET Mvc 4 web api
ASP.NET Mvc 4 web api
 
Web Services Tutorial
Web Services TutorialWeb Services Tutorial
Web Services Tutorial
 
Web services tutorial
Web services tutorialWeb services tutorial
Web services tutorial
 
REST API Recommendations
REST API RecommendationsREST API Recommendations
REST API Recommendations
 
Api 101
Api 101Api 101
Api 101
 
Rest ful tools for lazy experts
Rest ful tools for lazy expertsRest ful tools for lazy experts
Rest ful tools for lazy experts
 
RESTFul Tools For Lazy Experts - CFSummit 2016
RESTFul Tools For Lazy Experts - CFSummit 2016RESTFul Tools For Lazy Experts - CFSummit 2016
RESTFul Tools For Lazy Experts - CFSummit 2016
 
Rest with Spring
Rest with SpringRest with Spring
Rest with Spring
 
REST API Basics
REST API BasicsREST API Basics
REST API Basics
 
Documenting REST APIs
Documenting REST APIsDocumenting REST APIs
Documenting REST APIs
 
REST APIs
REST APIsREST APIs
REST APIs
 
Web Services PHP Tutorial
Web Services PHP TutorialWeb Services PHP Tutorial
Web Services PHP Tutorial
 
Building Awesome APIs with Lumen
Building Awesome APIs with LumenBuilding Awesome APIs with Lumen
Building Awesome APIs with Lumen
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 
Api crash
Api crashApi crash
Api crash
 

More from Oro Inc.

More from Oro Inc. (9)

Jary Carter Presents OroCRM
Jary Carter Presents OroCRMJary Carter Presents OroCRM
Jary Carter Presents OroCRM
 
Best Practices For Taking Your B2B Company Online
Best Practices For Taking Your B2B Company OnlineBest Practices For Taking Your B2B Company Online
Best Practices For Taking Your B2B Company Online
 
Oro Revolutionizes B2B Commerce - OroMeetup NL, 2017
Oro Revolutionizes B2B Commerce - OroMeetup NL, 2017Oro Revolutionizes B2B Commerce - OroMeetup NL, 2017
Oro Revolutionizes B2B Commerce - OroMeetup NL, 2017
 
Revolutionizing CRM market & B2B eCommerce - Oro MeetUp in Paris
Revolutionizing CRM market & B2B eCommerce - Oro MeetUp in ParisRevolutionizing CRM market & B2B eCommerce - Oro MeetUp in Paris
Revolutionizing CRM market & B2B eCommerce - Oro MeetUp in Paris
 
Oro London Meetup - dotmailer: Faster, smarter, better, email marketing
Oro London Meetup - dotmailer: Faster, smarter, better, email marketingOro London Meetup - dotmailer: Faster, smarter, better, email marketing
Oro London Meetup - dotmailer: Faster, smarter, better, email marketing
 
Webinar: “Create the Ultimate Customer Experience with Prestashop + OroCRM”
Webinar: “Create the Ultimate Customer Experience with Prestashop + OroCRM”Webinar: “Create the Ultimate Customer Experience with Prestashop + OroCRM”
Webinar: “Create the Ultimate Customer Experience with Prestashop + OroCRM”
 
11.17.15 Webinar: “Merchants: deliver an outstanding experience to your custo...
11.17.15 Webinar: “Merchants: deliver an outstanding experience to your custo...11.17.15 Webinar: “Merchants: deliver an outstanding experience to your custo...
11.17.15 Webinar: “Merchants: deliver an outstanding experience to your custo...
 
11.10.15 Webinar: “Improving Magento performance with Blackfire.io”
11.10.15 Webinar: “Improving Magento performance with Blackfire.io”11.10.15 Webinar: “Improving Magento performance with Blackfire.io”
11.10.15 Webinar: “Improving Magento performance with Blackfire.io”
 
OroCRM Multi-Channel Webinar
OroCRM Multi-Channel WebinarOroCRM Multi-Channel Webinar
OroCRM Multi-Channel Webinar
 

Recently uploaded

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
 
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
 

Recently uploaded (20)

Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
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, ...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
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
 
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
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
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
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
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
 
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...
 

Resting with OroCRM Webinar

  • 1. Agile Web Development Liip.ch – RESTING WITH Learn how to use and extend the OroCRM REST API
  • 2. AGENDA • Introduction to REST theory • How to discover OroCRM Rest APIs • How to use OroCRM REST APIs • How to add a new REST APIs to OroCRM
  • 4. Everyone who has ever talked about REST, at some point has said something idiotic about REST. Except for maybe Roy Fielding.
  • 5. For example, I once thought it meant converting all GET parameters to virtual directories. Differentiating GET and POST seemed like overzealous academics.
  • 6. I only began to understand why REST really makes sense and what REST it is really about when I started looking into cache headers and reverse proxies.
  • 7. REST is all about leveraging HTTP and constraining your application to a set of rules, so that users of your API can safely apply assumptions about the behavior of your application.
  • 8. HTTP Request Anatomy GET /notes HTTP/1.1 Host: symfony-rest-edition.lo Accept: application/json;q=0.9,*/*;q=0.8 Content-Type: application/json Content-Length: length
  • 9. HTTP Response Anatomy HTTP/1.1 200 OK Allow: GET, POST Cache-Control: max-age=15, public, s-maxage=30 Content-Type: application/json Date: Wed, 15 Jan 2014 15:09:01 GMT Last-Modified: Wed, 15 Jan 2014 14:09:03 GMT Server: Apache/2.2.24 (Unix) DAV/2 PHP/5.4.20 mod_ssl/ 2.2.24 OpenSSL/0.9.8y Vary: Accept-Encoding,Accept-Language {"notes":["a","b","c"]}
  • 11. RMM LEVEL 0 • Aka "The Swamp of POX" • HTTP as a tunneling mechanism • "Procedural" communication (RPC) • Single endpoint (per operation)
  • 13. RMM LEVEL 1 • Aka "Resources" • Individual resources, i.e. URIs • "Object orientated" communication
  • 15. RMM LEVEL 2 • Aka "HTTP Verbs" • Client uses specific HTTP method • Server uses HTTP status codes
  • 17. HTTP VERBS Method Safe Idempotent GET yes yes HEAD yes yes POST no no PUT no yes DELETE no yes (*) .. no no
  • 18. SAFE VS. IDEMPOTENT • Safe means cacheable • Idempotent means result independent of the # of executions, but.. • Does this apply to server state or also to the HTTP response? • Is DELETE idempotent or not, ie. what should be the response for a DELETE requests on a non existent resource? 404 or 200?
  • 19. HTTP STATUS CODES Code range Description Example 1xx Information 100 - Continue 2xx Successful 201 - Created 3xx Redirection 301 - Moved Permanently 4xx Client Error 404 - Not Found 5xx Server Error 501 - Not Implemented
  • 20. RMM LEVEL 3 • Aka "Hypermedia Control" • Service discovery via link relations • ATOM, HAL, JSON-LD, IANA Link Rel
  • 22. HYPERTEXT AS THE ENGINE OF APPLICATION STATE = HATEOAS
  • 23. RMM VS REST VS REAL LIFE • Most developers consider RMM Level 2 sufficient for REST • RMM Level 3 is a precondition but not sufficient for REST • ie. RMM only covers a subset of what REST requires • RMM Level 3 makes URI forma ing ma er less
  • 24. RMM VS REST VS REAL LIFE • Browsers are bad REST clients • REST is protocol independent • Few (no?) clients really leverage HATEOAS
  • 26. UNIFIED RESOURCE IDENTIFIER • URIs identify resources • URIs are format independent • URI "file extensions" != RESTful
  • 27. MEDIA TYPES • Identifies a representation format • Custom types use application/vnd.[XYZ] • Used inside the Accept / Content-Type headers Header Description Content-Type HTTP message format Accept HTTP response format preference
  • 28. • Finding appropriate response format • No standardized algorithm available • Apache mod_negotiation algorithm is documented • Also covers encoding (Accept-Encoding) and language (Accept- Language) negotiation CONTENT TYPE NEGOTIATION
  • 29. EXAMPLE Accept: application/json, application/xml;q=0.9, text/ html;q=0.8, text/*;q=0.7, */*;q=0.5 Priority Description q=1.0 application/json q=0.9 application/xml q=0.8 text/html q=0.7 text/* (ie. any text) q=0.5 */* (ie. any media type)
  • 30. OUT OF THE BOX OROCRM REST APIS • $> app/console router:debug | grep api • API Docs via NelmioApiDocBundle, ie. “/api/doc/“ • Enduser friendly API overview • Includes a sandbox to try out API calls • Information is extracted from Annotations on the Controllers
  • 31.
  • 32.
  • 33. USING OROCRM REST APIS • Constructing the URL for: api/rest/{version}/accounts/{id}.{_format} • Symfony uses a syntax based on RFC 6570 for templated URI • {version} = “v1” (recommended) or “latest” • {id} = ID of an Account instance • {_format} = lazy content type negotiation, ie. “.json”, or use HTTP header “Accept: application/json”
  • 34. http://httpie.org/ HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP client. Its goal is to make CLI interaction with web services as human-friendly as possible. It provides a simple “http” command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays colorized output. HTTPie can be used for testing, debugging, and generally interacting with HTTP servers.
  • 35. WSSE SECURITY $> http --json http://orocrm.lo/api/rest/v1/accounts HTTP/1.1 401 Unauthorized Cache-Control: no-cache Content-Type: application/json Date: Wed, 22 Jul 2015 12:09:08 GMT Server: Apache/2.4.10 (Unix) PHP/5.6.9 Set-Cookie: CRMID=i45n7g8phauhrfr2h53fh576q1; path=/; HttpOnly Transfer-Encoding: chunked WWW-Authenticate: WSSE realm="Secured API", profile="UsernameToken"
  • 36.
  • 37. GENERATING THE WSSE HEADER $> app/console oro:wsse:generate-header c51ef6cb3e87dcc6f077b93f0ceb778d23669364 To use WSSE authentication add following headers to the request: Authorization: WSSE profile="UsernameToken" X-WSSE: UsernameToken Username="admin", PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=", Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==", Created=“2015-07-22T14:12:27+02:00" http://www.orocrm.com/documentation/index/current/cookbook/how-to-use-wsse-authentication
  • 38. READING OROCRM REST APIS $> http --json http://orocrm.lo/api/rest/v1/accounts 'X-WSSE: UsernameToken Username="admin", PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=", Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==", Created=“2015-07-22T14:12:27+02:00"' [ { "contacts": {}, "createdAt": "2015-07-06T09:12:31+00:00", "defaultContact": "Mr. Jerry Coleman", "id": 1, "name": "Life Plan Counselling", "organization": "Liip Test",
  • 39. WRITING TO OROCRM REST APIS $> http POST --json http://orocrm.lo/api/rest/v1/accounts/1 'X-WSSE: UsernameToken Username="admin", PasswordDigest="pgkLCLmWcld9xkTUJ4Rxnj+Ww50=", Nonce="MjU3ZWMzYzI1ZTVmYjg5NA==", Created=“2015-07-22T14:12:27+02:00"' < account.json $> cat account.json { "account": { "owner": 2 } }
  • 41. APPROACHES TO CREATE A NEW API • OroCRM has uses various different approaches • Long term goal of OroCRM is to provide SOAP and REST via the same code • Available approaches: • Helper methods in Oro Platform RestGetController • Serialization via JMS Serializer or via Symfony core Serializer • Oro Platform EntitySerializer is a work in progress which make it even easier to cover REST and SOAP with the same controller
  • 42. BASIC CONTROLLER SETUP <?php
 
 namespace AcmeBundleCartBundleControllerApiRest;
 
 use FOSRestBundleControllerAnnotationsNamePrefix;
 use FOSRestBundleRoutingClassResourceInterface;
 use OroBundleSoapBundleControllerApiRestRestController;
 
 /**
 * @NamePrefix("acme_api_")
 */
 class CartController extends RestController implements ClassResourceInterface
 {
 .. }
  • 43. IMPLEMENTING GETTING A LIST (1/3) /**
 * REST GET list
 *
 * @ApiDoc(
 * description="Get all carts",
 * resource=true
 * )
 * @AclAncestor("orocrm_magento_cart_view")
 *
 * @return JsonResponse
 */
 public function cgetAction()
 {
 /** @var Cart[] $carts */
 $carts = $this->getManager()->getListQueryBuilder()->getQuery()->execute();
 
 return new JsonResponse(
 $this->getPreparedItems($carts, self::$fields),
 Codes::HTTP_OK
 );
 }
  • 44. IMPLEMENTING GETTING A LIST (2/3) <?php
 
 namespace AcmeBundleCartBundleControllerApiRest;
 use OroCRMBundleMagentoBundleEntityCart;
 
 use SymfonyComponentHttpFoundationJsonResponse;
 use FOSRestBundleControllerAnnotationsNamePrefix;
 use FOSRestBundleRoutingClassResourceInterface;
 use FOSRestBundleUtilCodes;
 use NelmioApiDocBundleAnnotationApiDoc;
 
 use OroBundleSecurityBundleAnnotationAclAncestor;
 use OroBundleSoapBundleControllerApiRestRestController; class CartController extends RestController implements ClassResourceInterface
 { static $fields = array('id', 'subTotal', 'grandTotal', 'taxAmount', 'customer') ..
 }
  • 45. IMPLEMENTING GETTING A LIST (3/3) /**
 * {@inheritdoc}
 */
 public function getManager()
 {
 return $this->get('acme.cart.manager.api');
 }
 
 /**
 * Prepare entity field for serialization
 *
 * @param string $field
 * @param mixed $value
 */
 protected function transformEntityField($field, &$value)
 {
 if ($value instanceof Customer) {
 $value = array('name' => $value->getLastName());
 return;
 }
 parent::transformEntityField($field, $value);
 }
  • 46. IMPLEMENTING GETTING A ONE ENTITY /**
 * REST GET one
 *
 * @ApiDoc(
 * description="Get one cart",
 * resource=true
 * )
 * @AclAncestor("orocrm_magento_cart_view")
 * @param int $cartId
 *
 * @return JsonResponse
 */
 public function getAction($cartId)
 {
 /** @var Cart $cart */
 $cart = $this->getManager()->find($cartId);
 
 return new JsonResponse(
 $this->getPreparedItem($cart, self::$fields),
 empty($cartId) ? Codes::HTTP_NOT_FOUND : Codes::HTTP_OK
 );
 }
  • 47. FULL EXAMPLE <?php
 
 namespace OroCRMBundleMagentoBundleControllerApiRest;
 
 use OroCRMBundleMagentoBundleEntityCustomer;
 use OroCRMBundleMagentoBundleEntityCart;
 
 use SymfonyComponentHttpFoundationJsonResponse;
 
 use FOSRestBundleControllerAnnotationsNamePrefix;
 use FOSRestBundleRoutingClassResourceInterface;
 use FOSRestBundleUtilCodes;
 
 use NelmioApiDocBundleAnnotationApiDoc;
 
 use OroBundleSecurityBundleAnnotationAclAncestor;
 use OroBundleSoapBundleControllerApiRestRestController;
 
 /**
 * @NamePrefix("acme_api_")
 */
 class CartController extends RestController implements ClassResourceInterface
 {
 static $fields = array('id', 'subTotal', 'grandTotal', 'taxAmount', 'customer');
 
 /**
 * REST GET list
 *
 * @ApiDoc(
 * description="Get all carts",
 * resource=true
 * )
 * @AclAncestor("orocrm_magento_cart_view")
 *
 * @return JsonResponse
 */
 public function cgetAction()
 {
 /** @var Cart[] $carts */
 $carts = $this->getManager()->getListQueryBuilder()->getQuery()->execute();
 
 return new JsonResponse(
 $this->getPreparedItems($carts, self::$fields),
 Codes::HTTP_OK
 );
 }
 /**
 * REST GET one
 *
 * @ApiDoc(
 * description="Get one cart",
 * resource=true
 * )
 * @AclAncestor("orocrm_magento_cart_view")
 * @param int $cartId
 *
 * @return JsonResponse
 */
 public function getAction($cartId)
 {
 /** @var Cart $cart */
 $cart = $this->getManager()->find($cartId);
 
 return new JsonResponse(
 $this->getPreparedItem($cart, self::$fields),
 empty($cartId) ? Codes::HTTP_NOT_FOUND : Codes::HTTP_OK
 );
 }
 
 public function getManager()
 {
 return $this->get('orocrm_magento.cart.manager.api');
 }
 
 protected function transformEntityField($field, &$value)
 {
 if ($value instanceof Customer) {
 $value = array('name' => $value->getLastName());
 return;
 }
 parent::transformEntityField($field, $value);
 }
 
 public function getFormHandler()
 {
 throw new BadMethodCallException('FormHandler is not available.');
 }
 }

  • 48. REQUIRED SERVICE # services.yml parameters: acme.cart.manager.api.class: OroBundleSoapBundle..ApiEntityManager
 services: acme.cart.manager.api:
 class: %acme.cart.manager.api.class%
 parent: oro_soap.manager.entity_manager.abstract
 arguments:
 - %orocrm_magento.entity.cart.class%
 - @doctrine.orm.entity_manager
  • 49. REQUIRED ROUTE DEFINITION # routing.yml acme_bundle_cart_api:
 resource: "@AcmeCartBundle/Controller/Api/Rest/CartController.php"
 type: rest
 prefix: api/rest/{version}
 requirements:
 version: latest|v1
 defaults:
 version: latest
  • 50. USING OUR NEW OROCRM REST API $> http --json http://orocrm.lo/api/rest/v1/carts ‘X-WSSE..’ .. [ { "customer": { "name": "Clark" }, "grandTotal": "163.9248", "id": 1, "subTotal": "163.9248", "taxAmount": "12.6748" },
  • 51. TESTING OROCRM REST APIS (1/2) use OroBundleTestFrameworkBundleTestWebTestCase;
 
 class ApiCartControllerTest extends WebTestCase
 {
 /* Taken from BazingaRestExtraBundle */
 protected function assertJsonResponse($response, $statusCode = 200)
 {
 $this->assertEquals(
 $statusCode, $response->getStatusCode(),
 $response->getContent()
 );
 $this->assertTrue(
 $response->headers->contains('Content-Type', 'application/json'),
 $response->headers
 );
 }
 
 protected function setUp()
 {
 $this->initClient(array(), $this->generateWsseAuthHeader());
 } ..

  • 52. TESTING OROCRM REST APIS (2/2) public function testGetCarts()
 {
 $this->client->request('HEAD', '/api/rest/v1/carts');
 $response = $this->client->getResponse();
 $this->assertEquals(200, $response->getStatusCode(), $response->getContent());
 
 $this->client->request('GET', ‘/api/rest/v1/carts');
 $response = $this->client->getResponse();
 
 $this->assertJsonResponse($response);
 $this->assertEquals(‘..’, $response->getContent());
 }
 
 public function testGetCart()
 {
 $this->client->request('GET', '/api/rest/v1/carts/1');
 $response = $this->client->getResponse();
 
 $this->assertJsonResponse($response);
 $this->assertEquals('{"id": 1,"subTotal":"163.9248","grandTotal":"163.9248","taxAmount":"12.6748","customer": {"name":"Clark"}}', $response->getContent());
 }