Sök…


Arbeta med RESTFul API

REpresentational State Transfer (REST) är en arkitektonisk stil som används för webbutveckling, introducerad och definierad 2000 av Roy Fielding.

Se det på wiki: REST wiki

Det är baserat på HTTP-protokoll ( HTTP på Wiki ), HTTP-förfrågningar (GET, POST, PATCH, DELETE ...) / svarskoder (404, 400, 200, 201, 500 ...) och kroppsstruktur.

Detta är ett utmärkt sätt att exponera dina data för ett annat system på Internet.

Föreställ dig att du vill göra en RESTFul-api för att hantera din StackOverFlower (användare) i din lokala databas.

Låt oss göra exemplet!

Symfony 2.8 ramverk

  1. Webbserver :

Du måste installera och konfigurera en webbserver på din lokala maskin, se Wamp eller Lamp eller Mamp : Du måste ha en ny version av PHP ( !!! Symfony krav !!! )

  1. Php cli och kompositör:

Du måste konfigurera PHP cli (varierande på vårt system), ange detta "PHP cli [OS-NAME] how-to" i vår vän Google! Du måste installera kompositör, se Kompositörinstallation

  1. Symfony:

Du måste installera Symfony 2.8 (med kompositör, det är det bättre sättet), öppna en terminal (eller cmd på windows) och gå till din webbserverväg.

Symfony 2 fungerar med en av de bättre strukturtyperna: buntar. Alla är paket på Symfony! Vi kan testa det ovan.

cd /your-web-server-path/
composer create-project symfony/framework-standard-edition example "2.8.*"

Gå till trädstrukturen och se: Symfony 2.8 är installerat i katalogen "exempel".

  1. FOSRest (för FriendsOfSymfony) på JMSSerializer Bundle:

Du måste installera dessa två paket:

JMSSerializer ( installera ):

composer require jms/serializer-bundle "~0.13"

FosRestBundle ( Installera ):

composer require friendsofsymfony/rest-bundle

Glöm inte att aktivera dem i AppKernel.php!

  1. Grundläggande konfiguration:

Gör din egen "Exempel" -bunt och skapa databasen.

cd /path/to/your/symfony/
php app/console generate:bundle
php app/console doctrine:generate:database

Gå till botten av din Symfony 2.8-programkonfigurationsfil och klistra in den:

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

Gör din lärarkatalog ("exempel / src / ExempelBundel / Enhet") och resursfil ("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

Generera enhets- och uppdateringsschema:

php app/console doctrine:generate:entity StackOverFlower
php app/console doctrine:schema:update --force

Skapa en standardkontroll:

#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);
    }
}

Gör din standardvy av Twig:

#src/ExampleBundle/Resources/views/StackOverFlower.html.twig
{% if errors is defined %}
  {{ errors }}  
{% else %}
  {% if users is defined %}
    {{ users | serialize }}
  {% else %}
    {{ user | serialize }}
  {% endif %}
{% endif %}

Du har precis gjort ditt första RESTFul API!

Du kan testa det på: http: //your-server-name/your-symfony-path/app_dev.php/stackoverflower/new/test .

Som du kan se i databasen har en ny användare skapats med namnet "test".

Du kan få listan med stackoverflower på: http: //your-server-name/your-symfony-path/app_dev.php/stackoverflowers

Du har ett fullständigt exempel på mitt github-konto av det här exemplet: Git Hub-exempel , på "master" -grenen detta exempel, och på "real-routes" -branschen ett exempel med mer lämplig URL (som POST och DELETE).

Vi ses senare för ett exempel med SOAP!

Vänliga hälsningar,

Mathieu

Arbeta med SOAP API

SOAP (Simple Access Object Protocol) är XML-baserat, som XML-RPC, är förfader , med filen som heter WSDL , vad som beskriver metoden som ska exponeras.

Detta protokoll är ofta baserat med SOAP-Enveloppe , en SOAP-kropp , och alternativt SOAP-Header , uppdateras data i en struktur och tolkas på samma sätt från olika språk.

Beskrivning av ett tvålmeddelande

För mer information, se: SOAP på wiki

Som beskrivits ovan är det viktigaste att beskriva din webbtjänst WSDL- filen, se: WSDL-förklaring på wiki

Det grundläggande i arbetet är att definiera vad som exponeras i ditt SOAP API, din klass och din affärsprocess hanteras automatiskt av den grundläggande PHP SOAPServer klassen. Du behöver fortfarande koden!

Låt oss se hur filen är konstruerad:

  1. Tjänst: Ställ in API URI och vad som kommer att associeras.
  2. Bindande: Det definierar de operationer som är kopplade till tjänsten
  3. Åtgärder: Vissa metoder du vill exponera på webben
  4. Porttyper: Definiera frågor och svar
  5. Begäran och svar: vad du förväntar dig input och output
  6. Meddelanden: vilket format du förväntar dig (parametrar) på varje IO, de kan vara enkla (sträng, heltal, flyta ...) eller komplex typ (strukturerat format)

Med denna grundläggande information kan du uppnå all API du vill ha.

Föreställ dig att du vill skapa en SOAP-api för att hantera din StackOverFlower (användare) i din lokala databas.

Låt oss göra exemplet!

Installera webbserver, Php cli, Composer, Symfony 2.8, skapa ett nytt paket "ExempelBundle" och bygg schemat som beskrivits ovan.

Innan vi började bygga vår affärslogik var vi tvungna att veta vad vi skulle avslöja för vår controller. Det här jobbet utförs med WSDL. Detta är ett exempel på en bra syntax för en 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>

Vi måste ta detta i din webbsymfonikatalog (i tvålens underkatalog, och namnge denna "stackoverflower.wsdl").

Verkligen inspirerad från WSDl Exempel . Du kan validera det med en online WSDl-validerare

Efter detta kan vi göra vår grundläggande service och controller, inspirerad av SOAP Symfony 2.8 Doc .

Service som hanteras av 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";
  }
}

Konfigurera den här tjänsten:

#src\ExampleBundle\Resources\config\services.yml
services:
  stackoverflower_service:
    class: ExampleBundle\Services\StackOverFlowerService
    arguments: [@doctrine.orm.entity_manager]

Som ni ser, injicerar vi Doctrine Entity Manger som ett beroende eftersom vi måste använda detta för att CRUD StackOverFlower-objekt.

Controller, som avslöjar serviceobjektet:

#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;
  }
}

För mer information om tjänster, se: Servicebehållare på Symfony doc

Rutten :

example_soap:
  path:     /soap
  defaults: { _controller: ExampleBundle:StackOverFlower:index }

Den grundläggande kvistmallen:

#src\ExampleBundle\Resources\views\Soap\default.html.twig
{% if status is defined %}
{{ status }}
{% else %}
{{ list }}
{% endif %}

Vi har gjort ditt första SOAP API med Symfony 2.8!

Innan du avslöjar det måste vi testa !!

Lägg till detta i din StackOverFlowerController:

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

Rutterna:

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 }

Du kan skriva detta i din webbläsare:

  1. getList
  2. ny
  3. redigera
  4. radera

Detta är ett mycket grundläggande exempel på ett icke-säkrat API med SOAP, jag kan göra ett exempel på ett säkert exempel bakom en api-nyckelverifiering senare.

Att alla människor ...

Mathieu



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow