a unified soap/json api with symfony2

18
A UNIFIED SOAP / JSON API using Symfony2 Tuesday, 12 June 12

Upload: craig-marvelley

Post on 08-May-2015

4.734 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: A Unified SOAP/JSON API with Symfony2

A UNIFIED SOAP / JSON APIusing Symfony2

Tuesday, 12 June 12

Page 2: A Unified SOAP/JSON API with Symfony2

ABOUT ME

• Craig Marvelley

•Developer at Box UK

•@craigmarvelley

• Using Symfony for ~ 1 year

Tuesday, 12 June 12

Page 3: A Unified SOAP/JSON API with Symfony2

WEBSITE

LEGACY APIS(SOAP)

MOBILE DEVICES

THE PROBLEM

Tuesday, 12 June 12

Page 4: A Unified SOAP/JSON API with Symfony2

WEBSITE

LEGACY APIS(SOAP)

MOBILE DEVICES

THE SOLUTION

FACADE API(SOAP/JSON)

SOAP

JSON

SOAP

Tuesday, 12 June 12

Page 5: A Unified SOAP/JSON API with Symfony2

Request

JSONController SOAPController

ProcessingService

JSON Response

/soap/json

SOAP Response

Tuesday, 12 June 12

Page 6: A Unified SOAP/JSON API with Symfony2

KEY COMPONENTS

• Individual request classes to encapsulate data

• A custom ParamConverter creates objects from JSON requests

•Objects created from SOAP requests according to WSDL

•WebserviceManager class performs processing and creates an individual response object

• Response is returned to appropriate controller, and output

Tuesday, 12 June 12

Page 7: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Request;

use BoxUK\Bundle\ApiBundle\Request;use Symfony\Component\Validator\Constraints as Assert;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;

/** * @Assert\Callback(methods={ * { "BoxUK\Bundle\ApiBundle\Request\Validator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest {

/** * @Assert\NotBlank() * @Soap\ComplexType("string") */ private $domainName;

public function setDomainName( $domainName ) { $this->domainName = $domainName; }

public function getDomainName() { return $this->domainName; }

}

Tuesday, 12 June 12

Page 8: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Request;

use BoxUK\Bundle\ApiBundle\Request;use Symfony\Component\Validator\Constraints as Assert;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;

/** * @Assert\Callback(methods={ * { "BoxUK\Bundle\ApiBundle\Request\Validator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest {

/** * @Assert\NotBlank() * @Soap\ComplexType("string") */ private $domainName;

public function setDomainName( $domainName ) { $this->domainName = $domainName; }

public function getDomainName() { return $this->domainName; }

}

Tuesday, 12 June 12

Page 9: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Request;

use BoxUK\Bundle\ApiBundle\Request;use Symfony\Component\Validator\Constraints as Assert;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;

/** * @Assert\Callback(methods={ * { "BoxUK\Bundle\ApiBundle\Request\Validator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest {

/** * @Assert\NotBlank() * @Soap\ComplexType("string") */ private $domainName;

public function setDomainName( $domainName ) { $this->domainName = $domainName; }

public function getDomainName() { return $this->domainName; }

}

Tuesday, 12 June 12

Page 10: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use BoxUK\Bundle\ApiBundle\Request\DomainInfoRequest;

/** * @Route("/json") */class JsonController extends Controller { /** * @Route("/domainInfo") * @Method("GET") */ public function domainInfoAction(DomainInfoRequest $request) { return $this->respond( $this->getManager()->domainInfo( $request ) ); }

/** * @return \BoxUK\Bundle\ApiBundle\Management\WebserviceManager */protected function getManager() { return $this->container->get( 'box_uk.api.webservice_manager' );}

....}

Tuesday, 12 June 12

Page 11: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Controller;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;use Symfony\Component\DependencyInjection\ContainerAware;

class SoapController extends ContainerAware { /** * @Soap\Method("domainInfo") * @Soap\Param("request", phpType = "BoxUK\Bundle\ApiBundle\Request\DomainInfoRequest") * @Soap\Result(phpType = "BoxUK\Bundle\ApiBundle\Response\DomainInfoRequest") */ public function domainInfoAction(DomainInfoRequest $request) { $response = $this->getManager()->domainInfo($request); return $this->respond($response); }

....}

Tuesday, 12 June 12

Page 12: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Controller;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;use Symfony\Component\DependencyInjection\ContainerAware;

class SoapController extends ContainerAware { /** * @Soap\Method("domainInfo") * @Soap\Param("request", phpType = "BoxUK\Bundle\ApiBundle\Request\DomainInfoRequest") * @Soap\Result(phpType = "BoxUK\Bundle\ApiBundle\Response\DomainInfoRequest") */ public function domainInfoAction(DomainInfoRequest $request) { $response = $this->getManager()->domainInfo($request); return $this->respond($response); }

....}

Tuesday, 12 June 12

Page 13: A Unified SOAP/JSON API with Symfony2

<?php

namespace BoxUK\Bundle\ApiBundle\Controller;use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;use Symfony\Component\DependencyInjection\ContainerAware;

class SoapController extends ContainerAware { /** * @param \BoxUK\Bundle\ApiBundle\Response $response * @return mixed */ protected function respond( $response ) {

if ( !$response->getSuccess() ) { $code = $response->getCode(); throw new \SoapFault(

$faultcode, $response->getErrorMessage(), null, $response->getErrorCode() );

}

return $this->getSoapResponse()->setReturnValue( $response ); }}

Tuesday, 12 June 12

Page 14: A Unified SOAP/JSON API with Symfony2

WEBSERVICE MANAGER

• Registered as a service in services.xml

• Injected into both JSON and SOAP controllers

• Validates request content according to annotations

• Handles communication with legacy webservice API

• Uses Monolog for fine-grained logging (error & activity)

• Uses Doctrine2 to access and persist data

• Constructs responsesTuesday, 12 June 12

Page 15: A Unified SOAP/JSON API with Symfony2

HANDY SYMFONY2 FEATURES

• Used a custom annotation serializer to transform objects into JSON

• Used a ParamConverter to transform Symfony Request into agnostic Request objects (JSON only)

• Used a kernel listener to automatically validate user’s access key (JSON only)

• Used commands with a crontab to perform periodic updates to the database

Tuesday, 12 June 12

Page 16: A Unified SOAP/JSON API with Symfony2

COOL BUNDLES

• BeSimpleSoapBundle - Provides SOAP integration for Symfony2, automatically serialize/deserialise data to objects. USES ZEND\SOAP!

• LiipFunctionalTestBundle - Enhanced functional tests, database caching

•DoctrineFixturesBundle - For maintaining test data for functional tests

•DoctrineMigrationsBundle - For versioning the database schema

Tuesday, 12 June 12

Page 17: A Unified SOAP/JSON API with Symfony2

TESTING

• Lots and lots of unit tests

• Functional tests for controller actions

• Used a developer-in-test

• He used SoapUI to create test cases

• Automated SOAP request/responses from WSDL

Tuesday, 12 June 12

Page 18: A Unified SOAP/JSON API with Symfony2

THANKS FOR LISTENING!https://joind.in/talk/view/6667

@craigmarvelley

Tuesday, 12 June 12