{"id":35,"date":"2024-11-06T10:00:00","date_gmt":"2024-11-06T16:00:00","guid":{"rendered":"https:\/\/douglasstarnes.dev\/?p=35"},"modified":"2024-11-03T09:02:13","modified_gmt":"2024-11-03T15:02:13","slug":"building-a-rest-api-with-fastapi","status":"publish","type":"post","link":"https:\/\/douglasstarnes.dev\/index.php\/2024\/11\/06\/building-a-rest-api-with-fastapi\/","title":{"rendered":"Building a REST API with FastAPI"},"content":{"rendered":"\n<p>In the <a href=\"https:\/\/douglasstarnes.dev\/index.php\/2024\/11\/02\/hello-fastapi\/\" data-type=\"post\" data-id=\"7\">previous post<\/a> we saw how to create a simple FastAPI application, run it with uvicorn and use the interactive documentation.  But that application only implemented an endpoint that handled GET requests.  In this post, we will see how to implement the other HTTP methods (POST, PUT, DELETE) to complete the API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Representing Data in FastAPI<\/h2>\n\n\n\n<p>One of the advantages of FastAPI is that it takes advantage of modern Python features including type hints.  We will see that FastAPI can validate the structure of a JSON payload if we define a type to represent it.  FastAPI is built upon the pydantic package that enforces Python type hints at runtime.  (by default, the Python interpreter ignores type hints)  pydantic provides a base class we can use to define the expected structure of a JSON payload.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from pydantic import BaseModel\n\nclass TodoItem(BaseModel):\n  id: int\n  task: str\n  complete: bool\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">from<\/span><span style=\"color: #D8DEE9FF\"> pydantic <\/span><span style=\"color: #81A1C1\">import<\/span><span style=\"color: #D8DEE9FF\"> BaseModel<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">class<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #8FBCBB; font-weight: bold\">BaseModel<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">int<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  task<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">str<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  complete<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">bool<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>As you might expect, each field in the TodoItem class is annotated with a type hint.  Now we can create a list of TodoItem to masquerade as a database until we integrate a real database in a later post.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"todo_db = [\n  TodoItem(id=1, task=&quot;Task One&quot;, complete=True),\n  TodoItem(id=2, task=&quot;Task Two&quot;, complete=False)\n]\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D8DEE9FF\">todo_db <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">[<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">id<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">task<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Task One<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">complete<\/span><span style=\"color: #81A1C1\">=True<\/span><span style=\"color: #ECEFF4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #88C0D0\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">id<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">2<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">task<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Task Two<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">complete<\/span><span style=\"color: #81A1C1\">=False<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">]<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Refactor the Existing Application<\/h2>\n\n\n\n<p>Before adding new endpoints for the POST, PUT and DELETE methods, we can refactor the existing GET endpoint to use type hints.  First, rename it to <code>get_all_todos <\/code>as this handler function will return the entire &#8220;database&#8221; of <code>TodoItem<\/code>s.  The <code>get<\/code> decorator has the <code>response_model <\/code>keyword argument that tells which type the handler function will return.  Here it will return a <code>List <\/code>of <code>TodoItem<\/code>.  The <code>List <\/code>type from the <code>typing <\/code>module needs to be imported.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from typing import List\n\n@api.get(&quot;\/&quot;, response_model=List[TodoItem])\ndef get_all_todos():\n  return todos\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">from<\/span><span style=\"color: #D8DEE9FF\"> typing <\/span><span style=\"color: #81A1C1\">import<\/span><span style=\"color: #D8DEE9FF\"> List<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">@<\/span><span style=\"color: #D08770\">api<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D08770\">get<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">\/<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">response_model<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">List<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #D8DEE9FF\">TodoItem<\/span><span style=\"color: #ECEFF4\">])<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">get_all_todos<\/span><span style=\"color: #ECEFF4\">():<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>If you run the application and invoke the root endpoint, it won&#8217;t behave any differently.  Notice though that the interactive documentation now includes information about the schema of the response.  And this schema is the <code>TodoItem <\/code>just added.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"736\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/01-3-1024x736.png\" alt=\"\" class=\"wp-image-39\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/01-3-1024x736.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/01-3-300x216.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/01-3-768x552.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/01-3.png 1197w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Also, notice that JSON returned looks the same as it did before.  As mentioned in the previous post, FastAPI will convert between Python types and JSON if possible.  FastAPI knows how to convert <code>BaseModel <\/code>subclasses into JSON so it did that here.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Retrieving Single TodoItems<\/h2>\n\n\n\n<p>Here is the route and handler function to get a single <code>TodoItem <\/code>by its unique id.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from fastapi import HTTPException\n\n@api.get(&quot;\/todo\/{todo_id}&quot;, response_model=TodoItem)\ndef get_todo_by_id(todo_id: int):\n  for todo in todos:\n    if todo.id == todo_id:\n      return todo\n  raise HTTPException(status_code=404, detail=&quot;TodoItem not found&quot;)\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">from<\/span><span style=\"color: #D8DEE9FF\"> fastapi <\/span><span style=\"color: #81A1C1\">import<\/span><span style=\"color: #D8DEE9FF\"> HTTPException<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">@<\/span><span style=\"color: #D08770\">api<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D08770\">get<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">\/todo\/<\/span><span style=\"color: #EBCB8B\">{todo_id}<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">response_model<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">TodoItem<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">get_todo_by_id<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">int<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">for<\/span><span style=\"color: #D8DEE9FF\"> todo <\/span><span style=\"color: #81A1C1\">in<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">if<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">id <\/span><span style=\"color: #81A1C1\">==<\/span><span style=\"color: #D8DEE9FF\"> todo_id<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">raise<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">HTTPException<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">status_code<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">404<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">detail<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">TodoItem not found<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>There are several new concepts in this snippet so let&#8217;s look at them.<\/p>\n\n\n\n<p>First, in the <code>get <\/code>decorator on line 3, the path includes a parameter named <code>todo_id<\/code>.  In other words, the value included in the second path segment, after <code>\/todo<\/code>, will be passed to the handler function.  In line 4, the handler function accepts an argument named <code>todo_id<\/code>. And it is annotated with the type hint <code>int<\/code>.  Thus trying to access the path <code>\/todo\/abc<\/code> would raise an error as &#8220;abc&#8221; cannot be converted to an integer.<\/p>\n\n\n\n<p>As this application is not (yet) using a real database, the process of looking for a <code>TodoItem <\/code>with an id is done by brute force.  Simply loop through the <code>todos <\/code>list and if a <code>TodoItem <\/code>with the selected <code>id <\/code>is found, return it.  If the end of the loop is reached on line 8, that means the <code>TodoItem <\/code>was not found.  In that case, raise an exception, an <code>HTTPException <\/code>in this case.  The <code>HTTPException <\/code>is imported on line 1 from the <code>fastapi <\/code>module.  The <code>HTTPException <\/code>expects a <code>status_code <\/code>and a <code>detail <\/code>message.  The <code>status_code <\/code>here is 404 as there was no <code>TodoItem <\/code>with the <code>todo_id<\/code>.  The <code>detail <\/code>message will be returned in the JSON payload from the handler function.<\/p>\n\n\n\n<p>Run the application and go to the \/docs path in the browser.  There is a new item for the \/todo\/{todo_id} path.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"274\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-1024x274.png\" alt=\"\" class=\"wp-image-42\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-1024x274.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-300x80.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-768x205.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-1536x410.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/02-2-2048x547.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Expand it, and click the <strong>Try it out<\/strong> button.  Notice that the docs have an input for the <code>todo_id <\/code>path parameter.  Also, under the parameter name, is a reminder that this should be an integer. This was derived from the type hint in the code.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"223\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-1024x223.png\" alt=\"\" class=\"wp-image-43\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-1024x223.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-300x65.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-768x167.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-1536x334.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/03-2-2048x445.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Enter 1 in the input box and click the blue <strong>Execute<\/strong> button.  Scroll down to see that the JSON representation of the <code>TodoItem <\/code>with an id of 1 has been returned.<\/p>\n\n\n\n<p>Now try to get an id of 100.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"423\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-1024x423.png\" alt=\"\" class=\"wp-image-45\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-1024x423.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-300x124.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-768x318.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-1536x635.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/04-2-2048x847.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>There is no <code>TodoItem <\/code>with an <code>id <\/code>of 100.  Therefore, the <code>HTTPException <\/code>is raised resulting in the 404 status code.  Also the detail message from the <code>HTTPException <\/code>is included in the response body.<\/p>\n\n\n\n<p>What happens if you try to get an id that can&#8217;t be converted into an integer?  Put &#8220;abc&#8221; in the input box and click the <strong>Execute<\/strong> button.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"298\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-1024x298.png\" alt=\"\" class=\"wp-image-46\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-1024x298.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-300x87.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-768x223.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-1536x447.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/05-1-2048x596.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The interactive docs won&#8217;t let you do this.  And it&#8217;s kind of disappointing because you don&#8217;t get to see the actual response if you tried to do this in an application.  The actual response is a 422 status code which means <em>Unprocessable Entity<\/em>.  This makes sense.  As the string &#8220;abc&#8221; cannot be converted into an integer, the value cannot be processed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adding New TodoItems<\/h2>\n\n\n\n<p>Adding a new <code>TodoItem <\/code>is done with the POST method. To route a POST request to a function handler, use the <code>post <\/code>decorator. Even though there is no parameter in the path, a <code>todo <\/code>parameter is expected by the <code>new_todo <\/code>function. This is because the <code>TodoItem <\/code>will be constructed from JSON data included in the body of the POST request. In addition to converting <code>BaseModel <\/code>subclasses to JSON like we saw in the GET endpoints, FastAPI can also convert JSON to <code>BaseModel <\/code>subclasses. The <code>todo <\/code>is then appended to the <code>todos <\/code>list. Don&#8217;t worry about conflicting ids right now, we&#8217;ll take care of that soon.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"@api.post(&quot;\/todo&quot;, response_model=TodoItem)\ndef new_todo(todo: TodoItem):\n  todos.append(todo)\n  return todo\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ECEFF4\">@<\/span><span style=\"color: #D08770\">api<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D08770\">post<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">\/todo<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">response_model<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">TodoItem<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">new_todo<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> TodoItem<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  todos<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">append<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9FF\">todo<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Run the application, expand the item for the <code>\/todo<\/code> POST request, and click the <strong>Try it out<\/strong> button.  A textarea contains a scaffolded JSON object with keys for the fields in the <code>TodoItem <\/code>class.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"370\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-1024x370.png\" alt=\"\" class=\"wp-image-52\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-1024x370.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-300x108.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-768x277.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-1536x554.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/06-1-2048x739.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Add values for a new <code>TodoItem<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"{\n  &quot;id&quot;: 100,\n  &quot;task&quot;: &quot;Task One Hundred&quot;,\n  &quot;complete&quot;: False\n}\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #8FBCBB\">id<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">100<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #8FBCBB\">task<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Task One Hundred<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #8FBCBB\">complete<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">False<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Press the <strong>Execute<\/strong> button. Scroll down and see the results.  The endpoint returned the new <code>TodoItem<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"141\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-1024x141.png\" alt=\"\" class=\"wp-image-53\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-1024x141.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-300x41.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-768x106.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-1536x212.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/07-1-2048x282.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Go back to the item for the<code> \/<\/code> path.  Expand the item, click the <strong>Try it now<\/strong> button, and the <strong>Execute<\/strong> button.  The returned JSON now includes item 100.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"263\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-1024x263.png\" alt=\"\" class=\"wp-image-54\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-1024x263.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-300x77.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-768x197.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-1536x394.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/08-2048x526.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Creating a DTO<\/h2>\n\n\n\n<p>In the current implementation, you could add a <code>TodoItem <\/code>to the &#8220;database&#8221; with the same <code>id <\/code>as an existing item and the application would allow it.  In addition, you have to explicitly set the <code>complete <\/code>field to <code>True <\/code>despite it making little sense to add a task to a todo list that it already completed.  In other words, when creating a new <code>TodoItem <\/code>you only need to provide the <code>task<\/code>.  The <code>id <\/code>should be automatically generated and the <code>complete <\/code>field should be set to <code>False<\/code>.<\/p>\n\n\n\n<p>To do this, we can create another subclass of <code>BaseModel <\/code>that contains only the <code>task<\/code>.  This is commonly referred to as a <em>Data Transfer Object<\/em> or <em>DTO<\/em>.  Create a new <code>BaseModel <\/code>subclass and call it <code>CreateTodoItem<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"class CreateTodoItem(BaseModel):\n  task: str\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">class<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">CreateTodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #8FBCBB; font-weight: bold\">BaseModel<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  task<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">str<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In the <code>new_todo <\/code>function, change the type of the <code>todo <\/code>parameter to <code>CreateTodoItem<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"def new_todo(todo: CreateTodoItem):\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">new_todo<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> CreateTodoItem<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>To make this work, you need to refactor how the todo list is implemented.  Right now it&#8217;s a <code>List <\/code>of <code>TodoItem<\/code>.  But it&#8217;s going to work better as a dictionary where the keys are the numeric <code>id<\/code>s and the values are <code>TodoItem<\/code>s.  First change the <code>todos <\/code>variable to a dictionary.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"todos = {\n  1: TodoItem(id=1, task=&quot;Task One&quot;, complete=True),\n  2: TodoItem(id=2, task=&quot;Task Two&quot;, complete=False),\n}\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D8DEE9FF\">todos <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">id<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">1<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">task<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Task One<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">complete<\/span><span style=\"color: #81A1C1\">=True<\/span><span style=\"color: #ECEFF4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #B48EAD\">2<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">id<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">2<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">task<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Task Two<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">complete<\/span><span style=\"color: #81A1C1\">=False<\/span><span style=\"color: #ECEFF4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In the <code>get_all_todos <\/code>function you need to return just the values of the dictionary.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"def get_all_todos():\n  return todos.values()\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">get_all_todos<\/span><span style=\"color: #ECEFF4\">():<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">values<\/span><span style=\"color: #ECEFF4\">()<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The implementation of <code>get_todo_by_id <\/code>is simplified.  Attempt to get the <code>todo_id <\/code>key from the dictionary and return it on line 3.  If the key doesn&#8217;t exist, <code>except<\/code> the <code>KeyError <\/code>and raise the <code>HTTPException<\/code> on line 5.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"def get_todo_by_id(todo_id: int):\n  try:\n    return todos[todo_id]\n  except KeyError:\n    raise HTTPException(status_code=404, detail=&quot;TodoItem not found&quot;)\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">get_todo_by_id<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">int<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">try<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #D8DEE9FF\">todo_id<\/span><span style=\"color: #ECEFF4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">except<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">KeyError<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">raise<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">HTTPException<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">status_code<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">404<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">detail<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">TodoItem not found<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>And in the <code>new_todo <\/code>function, get the maximum value from the keys on line 2.  Add one to it for the id of the new <code>TodoItem<\/code>.  Then use the <code>id <\/code>and the <code>task <\/code>from the <code>CreateItemTodo <\/code>DTO to create a new <code>TodoItem<\/code> on line 3.  Set the complete keyword argument to False.  Add the new TodoItem to the dictionary using the id as the key on line 4.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"def new_todo(todo: CreateTodoItem):\n  next_id = max(todos.keys()) + 1\n  new_todo = TodoItem(id=next_id, task=todo.task, complete=False)\n  todos[next_id] = new_todo\n  return new_todo\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">new_todo<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> CreateTodoItem<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  next_id <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">max<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9FF\">todos<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #88C0D0\">keys<\/span><span style=\"color: #ECEFF4\">())<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">+<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  new_todo <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">TodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">id<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">next_id<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">task<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">task<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">complete<\/span><span style=\"color: #81A1C1\">=False<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  todos<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #D8DEE9FF\">next_id<\/span><span style=\"color: #ECEFF4\">]<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> new_todo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> new_todo<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>You&#8217;ll see how much time this saves us when implementing updates with the PUT method.  But first, let&#8217;s create another new <code>TodoItem<\/code>.  Run the application, and expand the item in the interactive docs for the POST request.  Notice that the scaffolded JSON only has a key for the task.  Fill it in and click the <strong>Execute<\/strong> button.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"357\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-1024x357.png\" alt=\"\" class=\"wp-image-55\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-1024x357.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-300x105.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-768x268.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-1536x536.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/09-2048x714.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Take a look at the response body.  As there are already two <code>TodoItem<\/code>s in the dictionary with ids 1 and 2, the new <code>TodoItem <\/code>was given an id of 3.  Also, the <code>complete <\/code>key was set to <code>false <\/code>by default.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updating TodoItems<\/h2>\n\n\n\n<p>To update a <code>TodoItem <\/code>is done using a PUT request.  As you might have guessed there is a <code>put <\/code>decorator to route the URL to the handler function.  But the PUT request is going to be a little different.  First, we have to get an existing <code>TodoItem <\/code>to update.  Refactoring the todo list to be a dictionary has made that simple.  Next we only want to update the fields that have new values.  We do this by creating a new <code>UpdateTodoItem <\/code>DTO and make all of the fields optional.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from typing import Optional\n\nclass UpdateTodoItem(BaseModel):\n  task: Optional[str] = None\n  complete: Optional[bool] = None\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #81A1C1\">from<\/span><span style=\"color: #D8DEE9FF\"> typing <\/span><span style=\"color: #81A1C1\">import<\/span><span style=\"color: #D8DEE9FF\"> Optional<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">class<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">UpdateTodoItem<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #8FBCBB; font-weight: bold\">BaseModel<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  task<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> Optional<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #88C0D0\">str<\/span><span style=\"color: #ECEFF4\">]<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">None<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  complete<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> Optional<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #88C0D0\">bool<\/span><span style=\"color: #ECEFF4\">]<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">None<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>In this class, both <code>task <\/code>and <code>complete <\/code>are <code>Optional <\/code>with a default value of <code>None<\/code>.  Thus we need to check for the presence of <code>None <\/code>in each field.  If the field is <code>None<\/code>, do nothing.  Otherwise use the value in the DTO to update the existing <code>TodoItem<\/code>.  Here&#8217;s the handler function implementation.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"@api.put(&quot;\/todo\/{todo_id}&quot;, response_model=TodoItem)\ndef update_todo(todo_id: int, todo: UpdateTodoItem):\n  try:\n    updated_todo = todos[todo_id]\n    if todo.task is not None:\n      updated_todo.task = todo.task\n    if todo.complete is not None:\n      updated_todo.complete = todo.complete\n    return updated_todo\n  except KeyError:\n    raise HTTPException(status_code=404, detail=&quot;TodoItem not found&quot;)\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ECEFF4\">@<\/span><span style=\"color: #D08770\">api<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D08770\">put<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">\/todo\/<\/span><span style=\"color: #EBCB8B\">{todo_id}<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">response_model<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\">TodoItem<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">update_todo<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">int<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">todo<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> UpdateTodoItem<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">try<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    updated_todo <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #D8DEE9FF\">todo_id<\/span><span style=\"color: #ECEFF4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">if<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">task <\/span><span style=\"color: #81A1C1\">is<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">not<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">None<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      updated_todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">task <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">task<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">if<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">complete <\/span><span style=\"color: #81A1C1\">is<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">not<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">None<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">      updated_todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">complete <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> todo<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D8DEE9FF\">complete<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">return<\/span><span style=\"color: #D8DEE9FF\"> updated_todo<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">except<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">KeyError<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">raise<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">HTTPException<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">status_code<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">404<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">detail<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">TodoItem not found<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Also, notice the <code>put <\/code>decorator.  It has a path parameter for the <code>todo_id <\/code>which is reflected by the <code>todo_id <\/code>parameter in the <code>update_todo <\/code>function.  But the PUT request also has a JSON body with the update data.  So it has to passed to the <code>update_todo <\/code>function as well.<\/p>\n\n\n\n<p>Start the application and browse to the interactive documentation.  Expand the PUT endpoint for<code> \/todos\/{todo_id}<\/code> and click the <strong>Try it out <\/strong>button.  Notice the is an input box for the <code>todo_id <\/code>path parameter as well as a textarea with a scaffolded JSON object for the <code>UpdateTodoItem <\/code>DTO.  Even though in the UpdateTodoItem, the code marks both fields as optional, the interactive documentation still provides default values for both.  Let&#8217;s try it out.<\/p>\n\n\n\n<p>You still have to provide a valid <code>todo_id <\/code>so put 2 in the input box.  Then delete both fields from the JSON leaving an empty object.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"274\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-1024x274.png\" alt=\"\" class=\"wp-image-61\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-1024x274.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-300x80.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-768x206.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-1536x412.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/10-1-2048x549.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Click the <strong>Execute<\/strong> button and scroll down to the response body.  The response body contains the JSON for the updated <code>TodoItem<\/code>.  But the values for <code>task <\/code>and <code>complete <\/code>have not changed.  That&#8217;s because they were omitted from the request body JSON.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"141\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-1024x141.png\" alt=\"\" class=\"wp-image-62\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-1024x141.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-300x41.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-768x106.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-1536x212.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/11-2048x283.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Go back to the request body and add a key for <code>complete <\/code>and set it to <code>true<\/code>.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"284\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-1024x284.png\" alt=\"\" class=\"wp-image-63\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-1024x284.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-300x83.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-768x213.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-1536x426.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/12-2048x568.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Click the <strong>Execute<\/strong> button and notice in the response body now contains an updated value for <code>complete<\/code>.  But the value of <code>task<\/code>, which was omitted from the request JSON, has not changed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"140\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-1024x140.png\" alt=\"\" class=\"wp-image-64\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-1024x140.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-300x41.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-768x105.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-1536x210.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/13-2048x281.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Go to the endpoint for <code>\/<\/code> and execute it to get all of the <code>TodoItem<\/code>s and notice that the updated value of <code>complete <\/code>for item 2 has been persisted in the application.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"215\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-1024x215.png\" alt=\"\" class=\"wp-image-65\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-1024x215.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-300x63.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-768x161.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-1536x322.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/14-2048x430.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Deleting TodoItems<\/h2>\n\n\n\n<p>To delete a <code>TodoItem<\/code>, apply the <code>delete <\/code>decorator to a handler function.  The path will require a parameter <code>todo_id<\/code>.  The handler function will attempt to delete that key from the dictionary.  If the key does not exist, the it will raise a <code>KeyError<\/code>.  The application will then raise an <code>HTTPException <\/code>with a 404 status code.  <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"@api.delete(&quot;\/todo\/{todo_id}&quot;, status_code=204)\ndef delete_todo(todo_id: int):\n  try:\n    del todos[todo_id]\n    return\n  except KeyError:\n    raise HTTPException(status_code=404, detail=&quot;TodoItem not found&quot;)\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ECEFF4\">@<\/span><span style=\"color: #D08770\">api<\/span><span style=\"color: #ECEFF4\">.<\/span><span style=\"color: #D08770\">delete<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">\/todo\/<\/span><span style=\"color: #EBCB8B\">{todo_id}<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">status_code<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">204<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #81A1C1\">def<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">delete_todo<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">todo_id<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">int<\/span><span style=\"color: #ECEFF4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">try<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">del<\/span><span style=\"color: #D8DEE9FF\"> todos<\/span><span style=\"color: #ECEFF4\">[<\/span><span style=\"color: #D8DEE9FF\">todo_id<\/span><span style=\"color: #ECEFF4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #81A1C1\">except<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">KeyError<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #81A1C1\">raise<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #88C0D0\">HTTPException<\/span><span style=\"color: #ECEFF4\">(<\/span><span style=\"color: #D8DEE9\">status_code<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #B48EAD\">404<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #D8DEE9\">detail<\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">TodoItem not found<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Notice the use of the <code>status_code <\/code>keyword argument in the <code>delete <\/code>decorator.  A successful DELETE request should not return a response body but it should have a 204 status code.  And the handler function does not return a value.<\/p>\n\n\n\n<p>In the interactive documentation, deleting item number one returns no response body and a 204 status code.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"148\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-1024x148.png\" alt=\"\" class=\"wp-image-67\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-1024x148.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-300x43.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-768x111.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-1536x222.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/15-2048x296.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>And the list of <code>TodoItem<\/code>s contains only the second one.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"162\" src=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-1024x162.png\" alt=\"\" class=\"wp-image-68\" srcset=\"https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-1024x162.png 1024w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-300x47.png 300w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-768x121.png 768w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-1536x243.png 1536w, https:\/\/douglasstarnes.dev\/wp-content\/uploads\/2024\/11\/16-2048x324.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>In this post, you saw how to use FastAPI to complete a REST API.  You implemented the POST, PUT and DELETE methods.  You saw how to use the BaseModel class to structure the body of requests and responses.  And you used the interactive documentation to try things out.  Of course you could still use Postman to test the API or use requests to call it in code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post we saw how to create a simple FastAPI application, run it&#8230;<\/p>\n","protected":false},"author":1,"featured_media":70,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[3,4],"class_list":["post-35","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-fastapi","tag-fastapi","tag-python"],"_links":{"self":[{"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/posts\/35","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/comments?post=35"}],"version-history":[{"count":14,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/posts\/35\/revisions"}],"predecessor-version":[{"id":69,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/posts\/35\/revisions\/69"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/media\/70"}],"wp:attachment":[{"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/media?parent=35"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/categories?post=35"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/douglasstarnes.dev\/index.php\/wp-json\/wp\/v2\/tags?post=35"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}