Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ?valid, but the code we use can't be used in a real application.

We can Embed Resources Too

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

When we made our Battle endpoint, we decided it might be convenient to have a link to Programmer. It's just a nice thing to help our API clients. But to get that programmer's information, they're going to need to make a second request out to that URI. If it's really common to need the programmer information when you GET a battle, you may choose to put the Programmer's data, right inside the Battle's response.

What's really nice here is that HAL already has rules about how this should work:

    "_links": {
        "self": {
            "href": "http://example.org/api/user/matthew"
    "id": "matthew",
    "name": "Matthew Weier O'Phinney",
    "_embedded": {
        "contacts": [
                "_links": {
                    "self": {
                        "href": "http://example.org/api/user/mac_nibblet"
                "id": "mac_nibblet",
                "name": "Antoine Hedgecock"
                "_links": {
                    "self": {
                        "href": "http://example.org/api/user/spiffyjr"
                "id": "spiffyjr",
                "name": "Kyle Spraggs"

There's the _links section, but there's also an _embedded section. And our HATEOAS library will help us put stuff there.

Embedding a Resource

So let's try to embed our programmer into the battle. First, let's add a line to the scenario that looks for this. Let's look for _embedded, and we know it's going to be called programmer, and the data will live below this and we know one of the fields on a programmer is nickname. And we know this should be equal to Fred:

... lines 1 - 25
Scenario: GET one battle
Given there is a project called "projectA"
And there is a programmer called "Fred"
And there has been a battle between "Fred" and "projectA"
When I request "GET /api/battles/%battles.last.id%"
... lines 31 - 34
And the "_embedded.programmer.nickname" property should equal "Fred"
... lines 36 - 37

Let's make sure that fails first - and it does:

php vendor/bin/behat features/api/battle.feature:26

To make this work, we'll add more annotations to Battle. When you think of one resource relating to another - like how our Battle relates to the Programmer resource - there are 2 ways to express that relation. You can either link to it or you can embed it. Those are both just valid ways to think about expressing a link between 2 resources.

This @HATEOAS\Relation lets you do whichever you want. For a link, use the href. To embed something, use the embedded key and set it to an expression that points to which object you want to embed:

... lines 1 - 8
* @Hateoas\Relation(
* "programmer",
* href = @Hateoas\Route(
* "api_programmers_show",
* parameters = { "nickname" = "expr(object.programmer.nickname)" }
* ),
* embedded = "expr(object.programmer)"
* )
... line 18
class Battle
... lines 21 - 52

And actually, if you include both href and embedded, it'll create a link and embed it.

Before we run the test, add a "And print last response", because I like to see how my endpoints look. Let's run it:

php vendor/bin/behat features/api/battle.feature:26

Awesome it passes! If you look - HATEOAS is doing all the work for us. We still have _links, but we also have _embedded. What's cool is that it goes out to the Programmer resource and serializes it. You end up with all the same properties as normal, and you even end up with its links. So a lot of things are falling into place accidentally.

Prize: New Behat Definition

And just like with links, since embedded data always lives under _embedded, I have a built-in definition you can choose to use if you want to:

... lines 1 - 25
Scenario: GET one battle
... lines 27 - 34
And the embedded "programmer" should have a "nickname" property equal to "Fred"
... lines 36 - 37

Behind the scenes, this knows to look for all of this on the _embedded property.

And the test still passes. Now I'll take out the print last response. When it comes to linking and embedding, I hope you're feeling dangerous!

Leave a comment!

Login or Register to join the conversation
JuanLuisGarciaBorrego Avatar
JuanLuisGarciaBorrego Avatar JuanLuisGarciaBorrego | posted 4 years ago

Hi Ryan,

I have a question about the number of queries to the database when using JMSSerializer and HateoasBundle.

An entity A is associated with OneToOne to entity B through property $b.

class A
# If I put @Serializer\Expose() Internally it generates a query extra to get the data of the table B. It also happens if I use the embedded annotation.
private $b

This would be the right thing, but in my controller I have a query with join that pulls me all the data from both tables.
How do I do this with a single query? It's possible?

I have also tried to use fetch EAGER of doctrine, but still performing 2 query..

Any ideas?
Thank you very much


Hi Juan!

Hmm, it sounds like you correctly understand that if you query with a join, then the serializer should *not* be making these queries. So, this *is* weird! 2 things to check for:

1) If you Simply say $a->getB() in your controller (don't use the serializer temporarily), can you verify that the extra query is NOT made?

2) On your join, do you have an addSelect like described here? http://knpuniversity.com/sc...

In short, the serializer is kind of "stupid" - it simply knows that it should access the "b" property on A and use it to serialize into JSON. It doesn't know that Doctrine exists, and so shouldn't be interfering with how the queries are made for stuff. Well, that's how it *should* be working at least :).


Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ?valid, but the code we use can't be used in a real application.

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "silex/silex": "~1.0", // v1.3.2
        "symfony/twig-bridge": "~2.1", // v2.7.3
        "symfony/security": "~2.4", // v2.7.3
        "doctrine/dbal": "^2.5.4", // v2.5.4
        "monolog/monolog": "~1.7.0", // 1.7.0
        "symfony/validator": "~2.4", // v2.7.3
        "symfony/expression-language": "~2.4", // v2.7.3
        "jms/serializer": "~0.16", // 0.16.0
        "willdurand/hateoas": "~2.3" // v2.3.0
    "require-dev": {
        "behat/mink": "~1.5", // v1.5.0
        "behat/mink-goutte-driver": "~1.0.9", // v1.0.9
        "behat/mink-selenium2-driver": "~1.1.1", // v1.1.1
        "behat/behat": "~2.5", // v2.5.5
        "behat/mink-extension": "~1.2.0", // v1.2.0
        "phpunit/phpunit": "~5.7.0", // 5.7.27
        "guzzle/guzzle": "~3.7" // v3.9.3