A Unified SOAP/JSON API with Symfony2

0 views
5,903 views

Published on

Published in: Technology, Health & Medicine
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
0
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
37
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

A Unified SOAP/JSON API with Symfony2

  1. 1. A UNIFIED SOAP / JSON API using Symfony2Tuesday, 12 June 12
  2. 2. ABOUT ME • Craig Marvelley • Developer at Box UK • @craigmarvelley • Using Symfony for ~ 1 yearTuesday, 12 June 12
  3. 3. THE PROBLEM WEBSITE LEGACY APIS (SOAP) MOBILE DEVICESTuesday, 12 June 12
  4. 4. THE SOLUTION SOAP WEBSITE FACADE API SOAP LEGACY APIS (SOAP/JSON) (SOAP) JSON MOBILE DEVICESTuesday, 12 June 12
  5. 5. Request /json /soap JSONController SOAPController Processing Service JSON Response SOAP ResponseTuesday, 12 June 12
  6. 6. 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 outputTuesday, 12 June 12
  7. 7. <?phpnamespace BoxUKBundleApiBundleRequest;use BoxUKBundleApiBundleRequest;use SymfonyComponentValidatorConstraints as Assert;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;/** * @AssertCallback(methods={ * { "BoxUKBundleApiBundleRequestValidator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest { /** * @AssertNotBlank() * @SoapComplexType("string") */ private $domainName; public function setDomainName( $domainName ) { $this->domainName = $domainName; } public function getDomainName() { return $this->domainName; }}Tuesday, 12 June 12
  8. 8. <?phpnamespace BoxUKBundleApiBundleRequest;use BoxUKBundleApiBundleRequest;use SymfonyComponentValidatorConstraints as Assert;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;/** * @AssertCallback(methods={ * { "BoxUKBundleApiBundleRequestValidator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest { /** * @AssertNotBlank() * @SoapComplexType("string") */ private $domainName; public function setDomainName( $domainName ) { $this->domainName = $domainName; } public function getDomainName() { return $this->domainName; }}Tuesday, 12 June 12
  9. 9. <?phpnamespace BoxUKBundleApiBundleRequest;use BoxUKBundleApiBundleRequest;use SymfonyComponentValidatorConstraints as Assert;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;/** * @AssertCallback(methods={ * { "BoxUKBundleApiBundleRequestValidator", "isValidDomainName"} * }) */class DomainInfoRequest extends AbstractRequest { /** * @AssertNotBlank() * @SoapComplexType("string") */ private $domainName; public function setDomainName( $domainName ) { $this->domainName = $domainName; } public function getDomainName() { return $this->domainName; }}Tuesday, 12 June 12
  10. 10. <?phpnamespace BoxUKBundleApiBundleController;use SymfonyBundleFrameworkBundleControllerController;use BoxUKBundleApiBundleRequestDomainInfoRequest;/** * @Route("/json") */class JsonController extends Controller{ /** * @Route("/domainInfo") * @Method("GET") */ public function domainInfoAction(DomainInfoRequest $request) { return $this->respond( $this->getManager()->domainInfo( $request ) ); } /** * @return BoxUKBundleApiBundleManagementWebserviceManager */ protected function getManager() { return $this->container->get( box_uk.api.webservice_manager ); } ....}Tuesday, 12 June 12
  11. 11. <?phpnamespace BoxUKBundleApiBundleController;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;use SymfonyComponentDependencyInjectionContainerAware;class SoapController extends ContainerAware{ /** * @SoapMethod("domainInfo") * @SoapParam("request", phpType = "BoxUKBundleApiBundleRequestDomainInfoRequest") * @SoapResult(phpType = "BoxUKBundleApiBundleResponseDomainInfoRequest") */ public function domainInfoAction(DomainInfoRequest $request) { $response = $this->getManager()->domainInfo($request); return $this->respond($response); } ....}Tuesday, 12 June 12
  12. 12. <?phpnamespace BoxUKBundleApiBundleController;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;use SymfonyComponentDependencyInjectionContainerAware;class SoapController extends ContainerAware{ /** * @SoapMethod("domainInfo") * @SoapParam("request", phpType = "BoxUKBundleApiBundleRequestDomainInfoRequest") * @SoapResult(phpType = "BoxUKBundleApiBundleResponseDomainInfoRequest") */ public function domainInfoAction(DomainInfoRequest $request) { $response = $this->getManager()->domainInfo($request); return $this->respond($response); } ....}Tuesday, 12 June 12
  13. 13. <?phpnamespace BoxUKBundleApiBundleController;use BeSimpleSoapBundleServiceDefinitionAnnotation as Soap;use SymfonyComponentDependencyInjectionContainerAware;class SoapController extends ContainerAware{ /** * @param BoxUKBundleApiBundleResponse $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
  14. 14. 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
  15. 15. 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 databaseTuesday, 12 June 12
  16. 16. COOL BUNDLES • BeSimpleSoapBundle - Provides SOAP integration for Symfony2, automatically serialize/deserialise data to objects. USES ZENDSOAP! • LiipFunctionalTestBundle - Enhanced functional tests, database caching • DoctrineFixturesBundle - For maintaining test data for functional tests • DoctrineMigrationsBundle - For versioning the database schemaTuesday, 12 June 12
  17. 17. 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 WSDLTuesday, 12 June 12
  18. 18. THANKS FOR LISTENING! https://joind.in/talk/view/6667 @craigmarvelleyTuesday, 12 June 12

×