WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.046 --> 00:00:02.806 align:middle
Okay, this is cool...

00:00:03.076 --> 00:00:07.716 align:middle
but what about APIs and JavaScript
frontends and all that new fancy stuff?

00:00:08.156 --> 00:00:10.206 align:middle
How does Symfony stand up to that?

00:00:10.846 --> 00:00:16.926 align:middle
Actually, it stands up wonderfully: Symfony
is a first-class tool for building APIs.

00:00:17.666 --> 00:00:19.156 align:middle
Seriously, you're going to love it.

00:00:20.086 --> 00:00:25.336 align:middle
Since the world is now a mix of
traditional apps that return HTML and API's

00:00:25.336 --> 00:00:29.496 align:middle
that feed a JavaScript frontend, we'll
make an app that's a mixture of both.

00:00:30.466 --> 00:00:35.666 align:middle
Right now, the notes are rendered server-side
inside of the show.html.twig template.

00:00:36.116 --> 00:00:37.876 align:middle
But that's not awesome enough!

00:00:38.396 --> 00:00:43.516 align:middle
If an aquanaut adds a new comment, I need
to see it instantly, without refreshing.

00:00:44.296 --> 00:00:48.236 align:middle
To do that, we'll need an API endpoint
that returns the notes as JSON.

00:00:48.816 --> 00:00:53.046 align:middle
Once we have that, we can use JavaScript
to use that endpoint and do the rendering.

00:00:53.766 --> 00:00:56.436 align:middle
So how do you create API endpoints in Symfony?

00:00:57.036 --> 00:01:00.266 align:middle
Ok, do you remember what a
controller always returns?

00:01:00.766 --> 00:01:02.826 align:middle
Yes, a Response!

00:01:03.296 --> 00:01:03.956 align:middle
And ya know what?

00:01:04.266 --> 00:01:11.056 align:middle
Symfony doesn't care whether that holds HTML,
JSON, or a CSV of octopus research data.

00:01:12.026 --> 00:01:14.766 align:middle
So actually, this turns out to be really easy.

00:01:15.476 --> 00:01:18.726 align:middle
Create a new controller: I'll
call it getNotesAction().

00:01:20.006 --> 00:01:22.576 align:middle
This will return notes for a specific genus.

00:01:23.416 --> 00:01:29.616 align:middle
Use @Route("/genus/{genusName}/notes").

00:01:31.106 --> 00:01:35.186 align:middle
We really only want this endpoint to
be used for GET requests to this URL.

00:01:36.116 --> 00:01:43.776 align:middle
Add @Method("GET"): Without this, the route
will match a request using any HTTP method,

00:01:43.916 --> 00:01:44.646 align:middle
like POST.

00:01:44.646 --> 00:01:50.296 align:middle
But with this, the route will only match
if you make a GET request to this URL.

00:01:50.966 --> 00:01:52.186 align:middle
Did we need to do this?

00:01:52.506 --> 00:01:55.586 align:middle
Well no: but it's pretty
trendy in API's to think

00:01:55.586 --> 00:01:59.026 align:middle
about which HTTP method should
be used for each route.

00:01:59.926 --> 00:02:04.296 align:middle
Hmm, it's highlighting the
@Method as a missing import.

00:02:04.946 --> 00:02:10.226 align:middle
Ah! Don't forget when you use annotations,
let PhpStorm autocomplete them for you.

00:02:10.746 --> 00:02:15.506 align:middle
That's important because when you do that,
PhpStorm adds a use statement at the top

00:02:15.506 --> 00:02:20.286 align:middle
of the file that you need: If you forget this,
you'll get a pretty clear error about it.

00:02:21.546 --> 00:02:23.846 align:middle
Ok, let's see if Symfony sees the route!

00:02:24.266 --> 00:02:28.236 align:middle
Head to the console and run debug:router: Hey!

00:02:28.496 --> 00:02:31.916 align:middle
There's the new route at the
bottom, with its method set to GET.

00:02:32.966 --> 00:02:37.676 align:middle
Remove the $notes from the other controller:
we won't pass that to the template anymore:

00:02:37.676 --> 00:02:42.256 align:middle
In the new controller, I'll paste a new
$notes variable set to some beautiful data:

00:02:43.056 --> 00:02:47.546 align:middle
We're not using a database yet, but you can
already see that this kind of looks like it came

00:02:47.546 --> 00:02:52.426 align:middle
from one: it has a username, a photo
for each avatar, and the actual note.

00:02:53.066 --> 00:02:55.936 align:middle
It'll be pretty easy to make
this dynamic in the next episode.

00:02:55.936 --> 00:03:00.606 align:middle
Next, create a $data variable,
set it to an array,

00:03:00.606 --> 00:03:04.006 align:middle
and put the $notes in a notes
key inside of that.

00:03:04.006 --> 00:03:09.156 align:middle
Don't worry about this: I'm just creating
a future JSON structure I like: Now,

00:03:09.416 --> 00:03:12.286 align:middle
how do we finally return $data as JSON?

00:03:12.976 --> 00:03:19.976 align:middle
Simple: return new Response() and
pass it json_encode($data): Simple!

00:03:21.016 --> 00:03:22.726 align:middle
Hey, let's see if this works.

00:03:23.106 --> 00:03:26.186 align:middle
Copy the existing URL and add /notes at the end.

00:03:27.396 --> 00:03:32.476 align:middle
Congratulations, you've just created
your first Symfony API endpoint.

00:03:33.336 --> 00:03:35.666 align:middle
But you know, that could have been easier.

00:03:37.076 --> 00:03:41.176 align:middle
Replace the Response with new
JsonResponse and pass it $data

00:03:41.556 --> 00:03:45.106 align:middle
without the json_encode: This does two things.

00:03:45.476 --> 00:03:48.136 align:middle
First, it calls json_encode() for you.

00:03:48.516 --> 00:03:49.146 align:middle
Hey thanks!

00:03:49.636 --> 00:03:55.336 align:middle
And second, it sets the application/json
Content-Type header on the Response,

00:03:55.866 --> 00:03:58.256 align:middle
which we could have set manually,
but this is easier.

00:03:59.126 --> 00:04:02.966 align:middle
Refresh. It still works perfectly.

