maryisdead
maryisdead

Reputation: 1810

FOSRestBundle, generate URL to created resource

I'm in the process of creating a REST API with Symfony and the FOSRestBundle and am pretty much new to the both.

Now I wonder how to generate an URL to a resource I just created. Routes are setup like this:

# app/config/routing.yml

characters:
    type:     rest
    prefix:   /api
    resource: "@Optc/Resources/config/routing/characters_routing.yml"

NelmioApiDocBundle:
    prefix:   /api/doc
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
# Resources/Optc/Resources/config/routing/characters_routing.yml

characters:
    type:     rest
    resource: Optc\Controller\CharactersController

The part of the Characters controller that creates the resource:

    $character = new Character();
    $form = $this->createForm(new CharacterType(), $character);
    $form->bind($data);

    if ($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($character);
        $em->flush();

        $response->headers->set('Location', $this->generateUrl('get_characters', array('id' => $user->getId()), true));

        $view = $this->view($character, 200);
        return $this->handleView($view);
    }

Update: Full controller code:

<?php

namespace Optc\Controller;

use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\FOSRestController;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Optc\Entity\Character;
use Optc\Form\CharacterType;
use Optc\HttpFoundation\File\Base64File;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
* Characters Controller
*/
class CharactersController extends FOSRestController
{
    /**
     * Get the list of characters.
     *
     * @param string $page integer with the page number (requires param_fetcher_listener: force)
     *
     * @return array data
     *
     * @QueryParam(name="page", requirements="\d+", default="1", description="Page number of the overview.")
     * @ApiDoc()
     */
    public function getCharactersAction($page)
    {
        $characters = $this
            ->getDoctrine()
            ->getRepository('Optc:Character')
            ->findAll();

        $view = $this->view($characters, 200);
        return $this->handleView($view);
    }

    public function getCharacterAction($id)
    {
        $character = $this
            ->getDoctrine()
            ->getRepository('Optc:Character')
            ->findOneById($id);

        if (!$character) {
            throw new HttpException(404, sprintf('Character with id %d not found!', $id));
        }

        $view = $this->view($character, 200);
        return $this->handleView($view);
    }

    /**
     * Create a new character.
     *
     * @param Request $request
     *
     * @return View view instance
     *
     * @ApiDoc()
     */
    public function postCharacterAction(Request $request)
    {
        $data = $request->request->all();

        // If the request contains image date, first convert it from its base64 enconding to a real file
        if ($request->request->has('image') && $request->request->get('id')) {
            $imagePath = realpath($this->get('kernel')->getRootDir() . '/../web'.$this->container->getParameter('upload_path_characters')).'/'.$request->request->get('id');
            $file = Base64File::create($imagePath, $request->request->get('image'));
            $data['image'] = $file;
        }

        $character = new Character();
        $form = $this->createForm(new CharacterType(), $character);
        $form->bind($data);

        var_dump($form->isValid());
        var_dump($form->getErrorsAsString());

        var_dump($this->generateUrl('get_characters', array('id' => $character->getId()), true));
        die();

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($character);
            $em->flush();

            $response->headers->set('Location', $this->generateUrl('acme_demo_user_get', array('id' => $user->getId()), true));

            $view = $this->view($character, 200);
            return $this->handleView($view);
        }
        else {

        }
    }
}

The thing that isn't quite working like I expected is the generateUrl part to set the Location header. It spits out http://optc.local/api/characters?id=2. This will of course only list all resources instead. But what I want is http://optc.local/api/characters/2.

How would I do that? Seems like I'm missing something simple.

(By the way, the PHP part about returning the Location header is from http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/, so I expected this to be the "right" way.)

Upvotes: 0

Views: 1115

Answers (2)

Edwin O.
Edwin O.

Reputation: 5276

you should check app/console debug:router in terminal to see what name symfony has named the route

in my case it used a minus instead of an underscore

i.e get-character

Upvotes: 2

ghanbari
ghanbari

Reputation: 1629

You must use get_character route instead of get_characters route,

I suggest to you whether implement ClassResourceInterface or use RouteResource annotation, that can use method name as getAction, cgetAction(this is only a suggestion)

Upvotes: 1

Related Questions