dev-develop
dev-developEat your own dogfood!
MIT
The Requires
Eat your own dogfood!
Eating your own dog food, also called dogfooding, is a slang term used to reference a scenario in which a company uses its own product to test and promote the product., (*1)
With inspiration from Alex Bilbie and Jani Tarvainen, this project is a proof-of-concept written as a Symfony2 bundle., (*2)
Not currently considered stable or appropriate for production., (*3)
This is a proof of concept ONLY., (*4)
A lot of companies I have worked at have built a website, and then built the API. It's an after-thought. All of those companies however are small and can't afford the time or resources to properly implement microservice architecture., (*5)
This unfortunately meant that the API that was meant to compliment the product slowly lagged behind, as focus was on adding and improving features to the website - when demand for an API rose (for example, due to the boom in mobile usage) the project couldn't cope without major refactoring that could have been avoided., (*6)
If you have yet to build an API, I recommend reading Building APIs You Won't Hate. Totally worth it., (*7)
This bundle aims to bridge that gap by emulating some of the core design practices of microservices., (*8)
Dirty-hack-because-it-actually-uses-master-not-sub sub-requests via the HTTP kernel., (*9)
Yes, having two master requests within the lifetime of a Symfony application does cause issues. Yes, I am still finding out what those issues are., (*10)
This bundle is not intended to ever be a permant fixture or development tool. The moment you are comfortable with the concepts, you should plan your next project without it., (*11)
Imagine you have the following, simplified controller:, (*12)
<?php namespace AcmeBundle\Controller; use AcmeBundle\Entity\Product; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; class ProductController extends Controller { /** * @Route("/product/create") */ public function createAction() { $product = new Product; $product->setName('A Foo Bar'); $product->setPrice('19.99'); $product->setDescription('Lorem ipsum dolor'); $em = $this->getDoctrine()->getManager(); $em->persist($product); $em->flush(); return $this->render('AcmeBundle:Product:create.html.twig', [ 'name' => $product->getName(), ]); } }
The web controller cannot be re-used. Sure, we can refactor our code using OOP principles but that doesn't help the fact that the web controller is the main entry point for this create product functionality., (*13)
API controllers, however, deal purely in data without the contamination of HTML templates. If we put all of our logic into an API controller, we can create a "dogfood" request to the API., (*14)
<?php namespace AcmeBundle\Controller; use AcmeBundle\Entity\Product; use Darsyn\Bundle\DogfoodBundle\Response\ApiResponse; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Darsyn\Bundle\DogfoodBundle\Controller\Controller as DogfoodController; use Symfony\Component\HttpFoundation\Response; class ProductController extends DogfoodController { /** * @Route("/product/create") */ public function createAction() { $apiResponse = $this->dogfood('POST', '/api/product/create'); return $this->render( 'AcmeBundle:Product:create.html.twig', $apiResponse->getData() ); } /** * @Route("/api/product/create") */ public function apiCreateAction() { $product = new Product; $product->setName('A Foo Bar'); $product->setPrice('19.99'); $product->setDescription('Lorem ipsum dolor'); $em = $this->getDoctrine()->getManager(); $em->persist($product); $em->flush(); return new ApiResponse(['name' => $product->getName()]); } }
N.B. ApiResponse
is just an extension of Symfony's JsonResponse
. It outputs JSON if the API was requested, and provides the getData()
method if the API was requested internally., (*15)
There are two alternative methods for creating internal dogfood requests:, (*16)
<?php use Symfony\Component\HttpFoundation\Request; $apiResponse = $this->dogfoodRoute('name_of_route', $parameters = [], $data); $request = Request::create(); $apiResponse = $this->dogfoodRequest($request);
Eat your own dogfood!
MIT