AOEpeople / TYPO3_Restler

restler (PHP REST-Framework) for TYPO3
GNU General Public License v3.0
30 stars 17 forks source link

Unterschied zwischen GET und POST? #15

Closed hallihallo1 closed 7 years ago

hallihallo1 commented 7 years ago

Hallo,

seit ein paar Tagen versuche ich eine Schnittstelle mit Restler aufzubauen. Grundsätzlich habe ich sowohl GET-, als auch POST-Actions zum Laufen gebracht.

Nun allerdings möchte ich mit der Schnittstelle auf Models zugreifen, welche von der 'fe_users' aus TYPO3 erben. Hierfür habe ich in den Beispielen folgende Funktion gefunden: $this->loader->initializeFrontEndRendering($pageUid); Diese schien soweit auch zu funktionieren. Beim Abfragen einer Liste aller Datensätze aus dem entsprechenden Repository kam keine Fehlermeldung mehr.

/**
     * GET Action
     *
     * @url GET pages/{pageUid}
     * @param integer $pageUid {@min 1} The page-UID of your root-TYPO3-page
     * @return array {@type stdClass}
     */
    public function getAllKundes($pageUid)
    {
        $this->loader->initializeFrontEndRendering($pageUid);

        $restKundes = array();

        foreach ($this->kundeRepository->getAllArray() as $extbaseKunde) {
            /* @var $extbaseKunde Kunde */
            $restKunde = new stdClass();
            $restKunde->uid = $extbaseKunde->getUid();
            $restKunde->firstname = $extbaseKunde->getFirstName();
            $restKundes[] = $restKunde;
        }

        return $restKundes;
    }

Nun ist das Problem, dass ich auch eine POST-Action brauche, welche einen neuen Datensatz anlegen soll. Wenn ich hier die oben genannte Funktion verwendet, bekomme ich die Meldung: "Method Not Allowed". Falls ich sie allerdings wieder weg lasse, wir das TCA und somit auch das Mapping für die 'fe_users' nicht mehr geladen und er versucht eine Tabelle für 'verkaeufer' zu finden, welche nicht vorhanden ist.

Beide Repositorys sind auch ganz normal eingebunden:

/**
     * kundeRepository
     *
     * @var \myext\Domain\Repository\KundeRepository
     * @inject
     */
    protected $kundeRepository = NULL;

    /**
     * verkaeuferRepository
     *
     * @var \myext\Domain\Repository\VerkaeuferRepository
     * @inject
     */
    protected $verkaeuferRepository = NULL;
   /**
     * POST Action
     *
     * @url POST new
     * @status 201
     *
     * @param $data {@from body}
     * @throws RestException 400 Kunde is not valid
     * @return stdClass
     */
    public function newKunde($data)
    {
        $this->loader->initializeFrontEndRendering(1);

        $verkaeufer = $this->verkaeuferRepository->findByUid($data['uid']);

        try {
            $newKunde = new Kunde();
            $newKunde->setFirstName($data['firstname']);
            $newKunde->setLastName($data['lastname']);
            $newKunde->setVerkaeufer($verkaeufer);

            $this->kundeRepository->add($newKunde);
            $this->persistenceManager->persistAll();

        } catch(RestApiRequestException $e) {
            $this->throwRestException(self::HTTP_STATUS_CODE_BAD_REQUEST, 1446132826, $e->getMessage(), $e);
        }

    }

Durch mehrere Versuche ist mir allerdings aufgefallen, dass das Problem nicht auftritt, wenn ich zuerst eine GET-Action aufrufe, welche das FrontEndRendering initialisiert und erst dann den POST sende. Es scheint also tatsächlich nur an der Funktion zu legen.

Gibt es einen bestimmten Grund, warum diese in POST-Actions nicht erlaubt ist? Bzw. gibt es einen eleganteren Weg das Problem zu lösen? Danke.

soda-2005 commented 7 years ago

Hi, POST-actions in Kombination mit '$this->typo3Loader->initializeFrontEndUser' ist kein Problem. Das hab ich selber auch schon so verwendet. Die Fehlermeldung 'Method Not Allowed' scheint im restler-Framework 'definiert' zu sein...und zwar ist dass die Standard-Fehlermeldung, wenn restler einen 405-HTTP-Statuscode zurückliefert. Es deutet also darauf hin, dass du in deinem Code irgendetwas falsch/fehlerhaft konfiguriert hast ODER den Rest-Endpoint falsch aufrufst. Es hat aber definitiv nichts mit der restler-Extension zu tun.

Ich würde wie folgt vorgehen:

  1. Versuchen, den POST-Request mittels dem API-Explorer versuchen, aufzurufen. Wenn dies funktioniert, dann liegt's daran, wie du den POST-Request aus dem Frontend aufrufst.
  2. Wenn der POST-Request auch aus dem API-Explorer nicht aufgerufen werden kann, so müßtest du dich in restler 'reindebuggen'. Ich würde in diesem Fall prüfen, ob das restler-Framework an folgender Code-Stelle 'abbricht': Luracast\Restler\Routes::find (Zeile 454 - bzw. dort, wo der Code 'if ($status == 405) {' steht).

Durch mehrere Versuche ist mir allerdings aufgefallen, dass das Problem nicht auftritt, wenn ich zuerst eine GET-Action aufrufe, welche das FrontEndRendering initialisiert und erst dann den POST sende. Das iritiert mich, weil doch jeder REST-Endpoint-Aufruf für sich ein eigener PHP-Prozess darstellt?!? Also, wenn ich aus dem Client (z.B. browser) heraus 'POST www.mydomain.de/api/new' aufrufe, so ist das doch ein komplett eigener PHP-Prozess.

soda-2005 commented 7 years ago

...was mir noch auffällt (an deinem beispiel-code): Der phpDoc-code ist nicht korrekt/sauber definiert: @param $data... ...sollte aber besser lauten: @param array $data... Restler parst solchen phpDoc....evtl. kommt da restler durcheinander, weil du restler sagst, dass die variable im body definiert ist, du restler aber nicht sagst, von welchem type die variable ist...wobei ich jetzt natürlich nicht weiß ob der type ein array ist.

hallihallo1 commented 7 years ago

Erstmal danke für die Antwort. Lag tatsächlich am Aufruf des Endpoints. Im Postman haben wir diesen einfach immer über http://localhost/myproject/api/kunde/new aufgerufen. Im API-Explorer wird allerdings die URL https://localhost:443/myproject/api/kunde/new aufgerufen. Mit der funktioniert es nun auch im Postman. Scheint also tatsächlich nur am http bzw. https gelegen zu haben.

Die Variable ist tatsächlich ein Array. Wird gleich noch angepasst.