PATCH is (also) for Updating (basically)
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.
The main HTTP methods are: GET, POST, PUT and DELETE. There's another one you hear a lot about: PATCH.
The simple, but not entirely accurate definition of PATCH is this: it's just
like PUT, except you don't need to send up the entire resource body. If you
just want to update tagLine
, just send that field.
So really, PATCH is a bit nicer to work with than PUT, and we'll support
both. Start with the test - public function testPATCHProgrammer()
:
// ... lines 1 - 93 | |
public function testPATCHProgrammer() | |
{ | |
// ... lines 96 - 111 | |
} | |
// ... lines 113 - 125 |
Copy the inside of the PUT test: they'll be almost identical.
If you follow the rules with PUT, then if you don't send tagLine
, the
server should nullify it. Symfony's form system works like that, so our PUT
is acting right. Good PUT!
But for PATCH, let's only send tagLine
with a value of bar
. When we
do this, we expect tagLine
to be bar
, but we also expect avatarNumber
is still equal to 5. We're not sending avatarNumber
, which means: don't
change it. And change the method from put()
to patch()
:
// ... lines 1 - 93 | |
public function testPATCHProgrammer() | |
{ | |
$this->createProgrammer(array( | |
'nickname' => 'CowboyCoder', | |
'avatarNumber' => 5, | |
'tagLine' => 'foo', | |
)); | |
$data = array( | |
'tagLine' => 'bar', | |
); | |
$response = $this->client->patch('/api/programmers/CowboyCoder', [ | |
'body' => json_encode($data) | |
]); | |
$this->assertEquals(200, $response->getStatusCode()); | |
$this->asserter()->assertResponsePropertyEquals($response, 'avatarNumber', 5); | |
$this->asserter()->assertResponsePropertyEquals($response, 'tagLine', 'bar'); | |
} | |
// ... lines 112 - 124 |
In reality, PATCH can be more complex than this, and we talk about that in our other REST screencast (see The Truth Behind PATCH). But most API's make PATCH work like this.
Make sure the test fails - filter it for PATCH
to run just this one:
phpunit -c app --filter PATCH
Sweet! 405, method not allowed. Time to fix that!
Support PUT and PATCH
Since PUT and PATCH are so similar, we can handle them in the same action.
Just change the @Method
annotation to have a curly-brace with PUT
and
PATCH
inside of it:
// ... lines 1 - 87 | |
/** | |
* @Route("/api/programmers/{nickname}") | |
* @Method({"PUT", "PATCH"}) | |
*/ | |
public function updateAction($nickname, Request $request) | |
// ... lines 93 - 158 |
Now, this route accepts PUT or PATCH. Try the test again:
phpunit -c app --filter PATCH
Woh, 500 error! Integrity constraint: avatarNumber
cannot be null. It is
hitting our endpoint and because we're not sending avatarNumber
, the form
framework is nullifying it, which eventually makes the database yell at us.
The work of passing the data to the form is done in our private processForm()
method. And when it calls $form->submit()
, there's a second argument
called $clearMissing
. It's default value - true
- means that any missing
fields are nullified. But if you set it to false
, those fields are ignored.
That's perfect PATCH behavior. Create a new variable above this line called
$clearMissing
and set it to $request->getMethod() != 'PATCH'
:
// ... lines 1 - 139 | |
private function processForm(Request $request, FormInterface $form) | |
{ | |
$data = json_decode($request->getContent(), true); | |
$clearMissing = $request->getMethod() != 'PATCH'; | |
// ... line 145 | |
} | |
// ... lines 147 - 158 |
In other words, clear all the missing fields, unless the request method is PATCH. Pass this as the second argument:
// ... lines 1 - 139 | |
private function processForm(Request $request, FormInterface $form) | |
{ | |
$data = json_decode($request->getContent(), true); | |
$clearMissing = $request->getMethod() != 'PATCH'; | |
$form->submit($data, $clearMissing); | |
} | |
// ... lines 147 - 158 |
Head back, get rid of the big error message and run things again:
phpunit -c app --filter PATCH
Boom! We've got PUT
and PATCH
support with about 2 lines of code.
$form->submit($data, false) fails with "this value should not be null" validation error on PATCH for Symfony 4.3. Might have something to do with https://symfony.com/blog/ne...