Szukaj…
Pracuj z RESTFul API
REpresentational State Transfer (REST) to styl architektoniczny używany do tworzenia stron internetowych, wprowadzony i zdefiniowany w 2000 roku przez Roy Fieldinga.
Zobacz na wiki: REST wiki
Opiera się na protokole HTTP ( HTTP na Wiki ), żądaniach HTTP (GET, POST, PATCH, DELETE ...) / kodach odpowiedzi (404, 400, 200, 201, 500 ...) i strukturze treści.
To świetny sposób na udostępnienie danych innym systemowi w Internecie.
Wyobraź sobie, że chcesz utworzyć interfejs API RESTFul do zarządzania StackOverFlower (użytkownik) w lokalnej bazie danych.
Zróbmy przykład!
Framework Symfony 2.8
- Serwer internetowy :
Musisz zainstalować i skonfigurować serwer WWW na swoim komputerze lokalnym, zobacz Wamp lub Lamp lub Mamp : Musisz mieć najnowszą wersję PHP ( !!! Wymagania Symfony !!! )
- Php cli i kompozytor:
Musisz skonfigurować PHP cli (w zależności od naszego systemu), wpisać „PHP cli [NAZWA OS-a] w naszym przyjacielu Google! Musisz zainstalować kompozytora, patrz Instalacja kompozytora
- Symfony:
Musisz zainstalować Symfony 2.8 (z kompozytorem, to lepszy sposób), otworzyć terminal (lub cmd w systemie Windows) i przejść do ścieżki serwera WWW.
Symfony 2 działa z jednym z lepszych typów struktur: pakietami. Wszystkie są pakietami w Symfony! Możemy to przetestować powyżej.
cd /your-web-server-path/
composer create-project symfony/framework-standard-edition example "2.8.*"
Przejdź do struktury drzewa i zobacz: Symfony 2.8 jest zainstalowany w katalogu „example”.
- FOSRest (dla FriendsOfSymfony) w pakiecie JMSSerializer:
Musisz zainstalować te dwa pakiety:
JMSSerializer ( instalacja ):
composer require jms/serializer-bundle "~0.13"
FosRestBundle ( instalacja ):
composer require friendsofsymfony/rest-bundle
Nie zapomnij aktywować ich w AppKernel.php!
- Podstawowa konfiguracja:
Stwórz własny pakiet „Przykład” i utwórz bazę danych.
cd /path/to/your/symfony/
php app/console generate:bundle
php app/console doctrine:generate:database
Przejdź do dolnej części pliku konfiguracyjnego aplikacji Symfony 2.8 i wklej go:
#app/config/config.yml
fos_rest:
format_listener:
rules:
- { path: '^/stackoverflower', priorities: ['xml', 'json'], fallback_format: xml, prefer_extension: true }
- { path: '^/', priorities: [ 'text/html', '*/*'], fallback_format: html, prefer_extension: true }
Utwórz katalog doctrine („example / src / ExampleBundle / Entity”) i plik zasobów („StackOverFlower.orm.yml”):
# src/ExampleBundle/Resources/config/doctrine/StackOverFlower.orm.yml
ExampleBundle\Entity\StackOverFlower:
type: entity
table: stackoverflower
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 100
Generuj encję i aktualizuj schemat:
php app/console doctrine:generate:entity StackOverFlower
php app/console doctrine:schema:update --force
Stwórz domyślny kontroler:
#src/ExampleBundle/Controller/StackOverFlowerController.php
namespace ExampleBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\Delete;
use ExampleBundle\Entity\StackOverFlower;
class StackOverFlowerController extends FOSRestController
{
/**
* findStackOverFlowerByRequest
*
* @param Request $request
* @return StackOverFlower
* @throws NotFoundException
*/
private function findStackOverFlowerByRequest(Request $request) {
$id = $request->get('id');
$user = $this->getDoctrine()->getManager()->getRepository("ExampleBundle:StackOverFlower")->findOneBy(array('id' => $id));
return $user;
}
/**
* validateAndPersistEntity
*
* @param StackOverFlower $user
* @param Boolean $delete
* @return View the view
*/
private function validateAndPersistEntity(StackOverFlower $user, $delete = false) {
$template = "ExampleBundle:StackOverFlower:example.html.twig";
$validator = $this->get('validator');
$errors_list = $validator->validate($user);
if (count($errors_list) == 0) {
$em = $this->getDoctrine()->getManager();
if ($delete === true) {
$em->remove($user);
} else {
$em->persist($user);
}
$em->flush();
$view = $this->view($user)
->setTemplateVar('user')
->setTemplate($template);
} else {
$errors = "";
foreach ($errors_list as $error) {
$errors .= (string) $error->getMessage();
}
$view = $this->view($errors)
->setTemplateVar('errors')
->setTemplate($template);
}
return $view;
}
/**
* newStackOverFlowerAction
*
* @Get("/stackoverflower/new/{name}")
*
* @param Request $request
* @return String
*/
public function newStackOverFlowerAction(Request $request)
{
$user = new StackOverFlower();
$user->setName($request->get('name'));
$view = $this->validateAndPersistEntity($user);
return $this->handleView($view);
}
/**
* editStackOverFlowerAction
*
* @Get("/stackoverflower/edit/{id}/{name}")
*
* @param Request $request
* @return type
*/
public function editStackOverFlowerAction(Request $request) {
$user = $this->findStackOverFlowerByRequest($request);
if (! $user) {
$view = $this->view("No StackOverFlower found for this id:". $request->get('id'), 404);
return $this->handleView($view);
}
$user->setName($request->get('name'));
$view = $this->validateAndPersistEntity($user);
return $this->handleView($view);
}
/**
* deleteStackOverFlowerAction
*
* @Get("/stackoverflower/delete/{id}")
*
* @param Request $request
* @return type
*/
public function deleteStackOverFlowerAction(Request $request) {
$user = $this->findStackOverFlowerByRequest($request);
if (! $user) {
$view = $this->view("No StackOverFlower found for this id:". $request->get('id'), 404);
return $this->handleView();
}
$view = $this->validateAndPersistEntity($user, true);
return $this->handleView($view);
}
/**
* getStackOverFlowerAction
*
* @Get("/stackoverflowers")
*
* @param Request $request
* @return type
*/
public function getStackOverFlowerAction(Request $request) {
$template = "ExampleBundle:StackOverFlower:example.html.twig";
$users = $this->getDoctrine()->getManager()->getRepository("ExampleBundle:StackOverFlower")->findAll();
if (count($users) === 0) {
$view = $this->view("No StackOverFlower found.", 404);
return $this->handleView();
}
$view = $this->view($users)
->setTemplateVar('users')
->setTemplate($template);
return $this->handleView($view);
}
}
Ustaw domyślny widok gałązki:
#src/ExampleBundle/Resources/views/StackOverFlower.html.twig
{% if errors is defined %}
{{ errors }}
{% else %}
{% if users is defined %}
{{ users | serialize }}
{% else %}
{{ user | serialize }}
{% endif %}
{% endif %}
Właśnie utworzyłeś swój pierwszy interfejs API RESTFul!
Możesz to przetestować na: http: // twoja-nazwa-serwera/twoja-symfony-path/app_dev.php/stackoverflower/new/test .
Jak widać w bazie danych, utworzono nowego użytkownika o nazwie „test”.
Możesz uzyskać listę stackoverflower na stronie: http: //nazwa-serwera-serwis/twoja-symfony-path/app_dev.php/stackoverflowers
Masz pełny przykład na moim koncie github tego przykładu: przykład Git Hub , w gałęzi „master” ten przykład, a na „real-trasy” rozgałęzia się przykład z bardziej odpowiednim adresem URL (takim jak POST i DELETE).
Do zobaczenia później z przykładem SOAP!
Z poważaniem,
Mathieu
Pracuj z SOAP API
SOAP (Simple Access Object Protocol) jest oparty na XML, podobnie jak XML-RPC, jest przodkiem , z plikiem o nazwie WSDL , który opisuje metodę, która ma być ujawniona.
Protokół ten często opiera się na SOAP-Enveloppe , SOAP-Body i alternatywnie SOAP-Header , dane są otoczone strukturą i interpretowane w ten sam sposób z różnych języków.
Aby uzyskać więcej informacji, zobacz: SOAP na wiki
Jak opisano powyżej, najważniejsze do opisania twojej usługi internetowej jest plik WSDL , patrz: Objaśnienie WSDL na wiki
Podstawowym zadaniem będzie zdefiniowanie tego, co jest widoczne w interfejsie API SOAP, twoja klasa i proces biznesowy będą automatycznie obsługiwane przez podstawową klasę PHP SOAPServer . Nadal potrzebujesz kodu!
Zobaczmy, jak skonstruowany jest plik:
- Usługa: ustaw identyfikator URI interfejsu API i elementy, które zostaną powiązane.
- Wiązanie: określa operacje związane z usługą
- Operacje: niektóre metody, które chcesz udostępnić w Internecie
- PortTypes: definiuj zapytania i odpowiedzi
- Żądania i odpowiedzi: czego oczekujesz od danych wejściowych i wyjściowych
- Komunikaty: jakiego formatu oczekujesz (parametry) na każdym We / Wy, mogą być proste (łańcuch, liczba całkowita, liczba zmiennoprzecinkowa ...) lub typ złożony (format strukturalny)
Dzięki tym podstawowym informacjom możesz uzyskać wszystkie interfejsy API, jakie chcesz.
Wyobraź sobie, że chcesz utworzyć interfejs SOAP do zarządzania StackOverFlower (użytkownik) w lokalnej bazie danych.
Zróbmy przykład!
Zainstaluj serwer WWW, Php cli, Composer, Symfony 2.8, utwórz nowy pakiet „ExampleBundle” i zbuduj schemat jak opisano powyżej.
Zanim zaczęliśmy budować naszą logikę biznesową, musieliśmy wiedzieć, co ujawnić naszemu kontrolerowi. To zadanie jest wykonywane przy użyciu WSDL. To jest przykład dobrej składni WSDL:
<definitions name="StackOverFlowerService"
targetNamespace="http://example/soap/stackoverflower.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://example/soap/stackoverflower.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="NewRequest">
<part name="name" type="xsd:string"/>
</message>
<message name="NewResponse">
<part name="status" type="xsd:string"/>
</message>
<message name="getListRequest"></message>
<message name="getListResponse">
<part name="list" type="xsd:string"/>
</message>
<message name="editRequest">
<part name="id" type="xsd:string"/>
<part name="name" type="xsd:string"/>
</message>
<message name="editResponse">
<part name="status" type="xsd:string"/>
</message>
<message name="deleteRequest">
<part name="id" type="xsd:string"/>
</message>
<message name="deleteResponse">
<part name="status" type="xsd:string"/>
</message>
<portType name="StackOverFlower_PortType">
<operation name="newStack">
<input message="tns:NewRequest"/>
<output message="tns:NewResponse"/>
</operation>
<operation name="getList">
<input message="tns:getListRequest"/>
<output message="tns:getListResponse"/>
</operation>
<operation name="edit">
<input message="tns:editRequest"/>
<output message="tns:editResponse"/>
</operation>
<operation name="delete">
<input message="tns:deleteRequest"/>
<output message="tns:deleteResponse"/>
</operation>
</portType>
<binding name="StackOverFlower_Binding" type="tns:StackOverFlower_PortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="newStack">
<soap:operation soapAction="newStack"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:new"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:new"
use="encoded"/>
</output>
</operation>
<operation name="getList">
<soap:operation soapAction="getList"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:get-list"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:get-list"
use="encoded"/>
</output>
</operation>
<operation name="edit">
<soap:operation soapAction="edit"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:edit"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:edit"
use="encoded"/>
</output>
</operation>
<operation name="delete">
<soap:operation soapAction="delete"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:delete"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:delete"
use="encoded"/>
</output>
</operation>
</binding>
<service name="StackOverFlower_Service">
<documentation>Description File of StackOverFlowerService</documentation>
<port binding="tns:StackOverFlower_Binding" name="StackOverFlower_Port">
<soap:address
location="http://example/stackoverflower/" />
</port>
</service>
</definitions>
Musimy wziąć to do twojego internetowego katalogu symfony (w podkatalogu mydło i nazwać to „stackoverflower.wsdl”).
Naprawdę zainspirowany przykładem WSDl . Możesz to sprawdzić za pomocą walidatora WSDl Online
Następnie możemy uczynić naszą podstawową usługę i kontroler inspirowanymi SOAP Symfony 2.8 Doc .
Usługa obsługiwana przez PHP SOAPServer:
#src\ExampleBundle\Services\StackOverFlowerService.php
namespace ExampleBundle\Services;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use ExampleBundle\Entity\StackOverFlower;
class StackOverFlowerService
{
private $em;
private $stackoverflower;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function newStack($name)
{
$stackoverflower = new StackOverFlower();
$stackoverflower->setName($name);
$this->em->persist($stackoverflower);
$this->em->flush();
return "ok";
}
public function getList()
{
$stackoverflowers = $this->em->getRepository("ExampleBundle:StackOverFlower")->findAll();
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
return $serializer->serialize($stackoverflowers, 'json');
}
public function edit($id, $name)
{
$stackoverflower = $this->em->getRepository("ExampleBundle:StackOverFlower")->findOneById($id);
$stackoverflower->setName($name);
$this->em->persist($stackoverflower);
$this->em->flush();
return "ok";
}
public function delete($id)
{
$stackoverflower = $this->em->getRepository("ExampleBundle:StackOverFlower")->findOneById($id);
$this->em->remove($stackoverflower);
$this->em->flush();
return "ok";
}
}
Skonfiguruj tę usługę:
#src\ExampleBundle\Resources\config\services.yml
services:
stackoverflower_service:
class: ExampleBundle\Services\StackOverFlowerService
arguments: [@doctrine.orm.entity_manager]
Jak widać, wstrzykujemy Doctrine Entity Manger jako zależność, ponieważ musimy go użyć do CRUD StackOverFlower Object.
Kontroler, który udostępnia obiekt usługi:
#src\ExampleBundle\Controller\StackOverFlowerController.php
namespace ExampleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class StackOverFlowerController extends Controller
{
public function indexAction()
{
ini_set("soap.wsdl_cache_enabled", "0");
$options = array(
'uri' => 'http://example/app_dev.php/soap',
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true
);
$server = new \SoapServer(dirname(__FILE__).'/../../../**web/soap/stackoverflower.wsdl**', $options);
$server->setObject($this->get('stackoverflower_service'));
$response = new Response();
$response->headers->set('Content-Type', 'text/xml; charset=utf-8');
ob_start();
$server->handle();
$response->setContent(ob_get_clean());
return $response;
}
}
Aby dowiedzieć się więcej o usługach, zobacz: Kontener usług w dokumencie Symfony
Trasa :
example_soap:
path: /soap
defaults: { _controller: ExampleBundle:StackOverFlower:index }
Podstawowy szablon gałązki:
#src\ExampleBundle\Resources\views\Soap\default.html.twig
{% if status is defined %}
{{ status }}
{% else %}
{{ list }}
{% endif %}
Zrobiliśmy twój pierwszy SOAP API z Symfony 2.8!
Zanim go ujawnisz, musimy przetestować !!
W swoim StackOverFlowerController dodaj to:
public function testNewAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->newStack($request->query->get('name'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('status' => $result));
}
public function testEditAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->edit($request->query->get('id'), $request->query->get('name'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('status' => $result));
}
public function testGetListAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->getList();
return $this->render('ExampleBundle:Soap:default.html.twig', array('list' => $result));
}
public function testDeleteAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->delete($request->query->get('id'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('list' => $result));
}
// To test this from an another server, you can type this :
// $client = new \SoapClient("http://example/app_dev.php/soap?wsdl", array("trace" => 1, "exception" => 1));
// $result = $client->newStack($request->query->get('name'));
// print_r($result);
Trasy:
test_new:
path: /stackoverflower/new
defaults: { _controller: ExampleBundle:StackOverFlower:testNew }
test_edit:
path: /stackoverflower/edit
defaults: { _controller: ExampleBundle:StackOverFlower:testEdit }
test_get_list:
path: /stackoverflower/get-list
defaults: { _controller: ExampleBundle:StackOverFlower:testGetList }
test_delete:
path: /stackoverflower/delete
defaults: { _controller: ExampleBundle:StackOverFlower:testDelete }
Możesz wpisać to w swojej przeglądarce:
Jest to bardzo podstawowy przykład niezabezpieczonego interfejsu API z SOAP, później mogę zrobić przykład zabezpieczonego przykładu uwierzytelnienia za pomocą klucza API.
Że wszyscy ludzie ...
Mathieu