{"id":113669,"date":"2020-06-01T08:00:00","date_gmt":"2020-06-01T08:00:00","guid":{"rendered":"https:\/\/fedoramagazine.org\/?p=31024"},"modified":"2020-06-01T08:00:00","modified_gmt":"2020-06-01T08:00:00","slug":"use-fastapi-to-build-web-services-in-python","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2020\/06\/01\/use-fastapi-to-build-web-services-in-python\/","title":{"rendered":"Use FastAPI to build web services in Python"},"content":{"rendered":"<p><em><a href=\"https:\/\/fastapi.tiangolo.com\/\">FastAPI<\/a><\/em> is a modern Python web framework that leverage the latest Python improvement in asyncio. In this article you will see how to set up a container based development environment and implement a small web service with FastAPI.<\/p>\n<p> <span id=\"more-31024\"><\/span> <\/p>\n<h2>Getting Started<\/h2>\n<p>The development environment can be set up using the Fedora container image. The following Dockerfile prepares the container image with FastAPI, <a href=\"https:\/\/www.uvicorn.org\/\">Uvicorn<\/a> and <a href=\"https:\/\/github.com\/Tinche\/aiofiles\">aiofiles<\/a>.<\/p>\n<pre class=\"wp-block-preformatted\">FROM fedora:32\nRUN dnf install -y python-pip \\ &amp;&amp; dnf clean all \\ &amp;&amp; pip install fastapi uvicorn aiofiles\nWORKDIR \/srv\nCMD [\"uvicorn\", \"main:app\", \"--reload\"]<\/pre>\n<p>After saving this Dockerfile in your working directory, build the container image using podman.<\/p>\n<pre class=\"wp-block-preformatted\">$ podman build -t fastapi .\n$ podman images\nREPOSITORY TAG IMAGE ID CREATED SIZE\nlocalhost\/fastapi latest 01e974cabe8b 18 seconds ago 326 MB<\/pre>\n<p>Now let&#8217;s create a basic FastAPI program and run it using that container image.<\/p>\n<pre class=\"wp-block-preformatted\">from fastapi import FastAPI app = FastAPI() @app.get(\"\/\")\nasync def root(): return {\"message\": \"Hello Fedora Magazine!\"}<\/pre>\n<p>Save that source code in a <em>main.py<\/em> file and then run the following command to execute it:<\/p>\n<pre class=\"wp-block-preformatted\">$ podman run --rm -v $PWD:\/srv:z -p 8000:8000 --name fastapi -d fastapi\n$ curl http:\/\/127.0.0.1:8000\n{\"message\":\"Hello Fedora Magazine!\"<\/pre>\n<p>You now have a running web service using FastAPI. Any changes to <em>main.py<\/em> will be automatically reloaded. For example, try changing the &#8220;Hello Fedora Magazine!&#8221; message.<\/p>\n<p>To stop the application, run the following command. <\/p>\n<pre class=\"wp-block-preformatted\">$ podman stop fastapi<\/pre>\n<h2>Building a small web service<\/h2>\n<p>To really see the benefits of FastAPI and the performance improvement it brings (<a href=\"https:\/\/www.techempower.com\/benchmarks\/#section=test&amp;runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&amp;hw=ph&amp;test=composite&amp;l=z8kflr-v&amp;a=2&amp;f=jz8cg-0-3s-0-3k-6bo-0-0-18y74-8s5c-0\">see comparison<\/a> with other Python web frameworks), let&#8217;s build an application that manipulates some I\/O. You can use the output of the <em>dnf history<\/em> command as data for that application.<\/p>\n<p>First, save the output of that command in a file.<\/p>\n<pre class=\"wp-block-preformatted\">$ dnf history | tail --lines=+3 &gt; history.txt<\/pre>\n<p>The command is using <em>tail<\/em> to remove the headers of <em>dnf history<\/em> which are not needed by the application. Each dnf transaction can be represented with the following information: <\/p>\n<ul>\n<li>id : number of the transaction (increments every time a new transaction is run)<\/li>\n<li>command : the dnf command run during the transaction<\/li>\n<li>date: the date and time the transaction happened<\/li>\n<\/ul>\n<p>Next, modify the <em>main.py<\/em> file to add that data structure to the application.<\/p>\n<pre class=\"wp-block-preformatted\">from fastapi import FastAPI\nfrom pydantic import BaseModel app = FastAPI() class DnfTransaction(BaseModel): id: int command: str date: str<\/pre>\n<p>FastAPI comes with the <a href=\"https:\/\/pydantic-docs.helpmanual.io\/\">pydantic<\/a> library which allow you to easily build data classes and benefit from type annotation to validate your data.<\/p>\n<p>Now, continue building the application by adding a function that will read the data from the <em>history.txt <\/em> file.<\/p>\n<pre class=\"wp-block-preformatted\">import aiofiles from fastapi import FastAPI\nfrom pydantic import BaseModel app = FastAPI() class DnfTransaction(BaseModel): id: int command: str date: str async def read_history(): transactions = [] async with aiofiles.open(\"history.txt\") as f: async for line in f: transactions.append(DnfTransaction( id=line.split(\"|\")[0].strip(\" \"), command=line.split(\"|\")[1].strip(\" \"), date=line.split(\"|\")[2].strip(\" \"))) return transactions<\/pre>\n<p>This function makes use of the <em><a href=\"https:\/\/github.com\/Tinche\/aiofiles\">aiofiles<\/a><\/em> library which provides an asyncio API to manipulate files in Python. This means that opening and reading the file will not block other requests made to the server.<\/p>\n<p>Finally, change the root function to return the data stored in the transactions list.<\/p>\n<pre class=\"wp-block-preformatted\">@app.get(\"\/\")\nasync def read_root(): return await read_history()<\/pre>\n<p>To see the output of the application, run the following command<\/p>\n<pre class=\"wp-block-preformatted\">$ curl http:\/\/127.0.0.1:8000 | python -m json.tool\n[\n{ \"id\": 103, \"command\": \"update\", \"date\": \"2020-05-25 08:35\"\n},\n{ \"id\": 102, \"command\": \"update\", \"date\": \"2020-05-23 15:46\"\n},\n{ \"id\": 101, \"command\": \"update\", \"date\": \"2020-05-22 11:32\"\n},\n....\n]<\/pre>\n<h2>Conclusion<\/h2>\n<p><em>FastAPI<\/em> is gaining a lot a popularity in the Python web framework ecosystem because it offers a simple way to build web services using asyncio. You can find more information about <em>FastAPI<\/em> in the <a href=\"https:\/\/fastapi.tiangolo.com\/\">documentation<\/a>.<\/p>\n<p>The code of this article is available in <a href=\"https:\/\/github.com\/cverna\/fastapi_app\">this GitHub repository<\/a>.<\/p>\n<hr class=\"wp-block-separator\" \/>\n<p><em>Photo by&nbsp;<a href=\"https:\/\/unsplash.com\/@jankubita?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Jan Kubita<\/a>&nbsp;on&nbsp;<a href=\"https:\/\/unsplash.com\/s\/photos\/fast-snake?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash<\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>FastAPI is a modern Python web framework that leverage the latest Python improvement in asyncio. In this article you will see how to set up a container based development environment and implement a small web service with FastAPI. Getting Started The development environment can be set up using the Fedora container image. The following Dockerfile [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[107,1031,45,42,46,47,468,44,350,1032],"class_list":["post-113669","post","type-post","status-publish","format-standard","hentry","category-fedora-os","tag-containers","tag-fastapi","tag-fedora","tag-for-developers","tag-magazine","tag-news","tag-python","tag-using-software","tag-web-development","tag-web-services"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/113669","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=113669"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/113669\/revisions"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=113669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=113669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=113669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}