{"id":7034,"date":"2025-09-25T16:38:30","date_gmt":"2025-09-25T16:38:30","guid":{"rendered":"https:\/\/techtrendfeed.com\/?p=7034"},"modified":"2025-09-25T16:38:31","modified_gmt":"2025-09-25T16:38:31","slug":"constructing-a-video-recreation-recommender-system-with-fastapi-postgresql-and-render-half-2","status":"publish","type":"post","link":"https:\/\/techtrendfeed.com\/?p=7034","title":{"rendered":"Constructing a Video Recreation Recommender System with FastAPI, PostgreSQL, and Render: Half\u00a02"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<h2 class=\"wp-block-heading\">Getting Began<\/h2>\n<p class=\"wp-block-paragraph\">In <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/towardsdatascience.com\/building-video-game-recommender-systems-with-fastapi-postgresql-and-render-part-1\" target=\"_blank\" rel=\"noreferrer noopener\">half 1<\/a> we walked by way of the method of organising a board sport suggestion system leveraging FastAPI and PostgreSQL. In Half 2 we proceed this challenge and present how you can deploy this challenge to a cloud service, on this case Render, to make it accessible to customers.<\/p>\n<p class=\"wp-block-paragraph\">To make this a actuality, we\u2019ll be engaged on organising our PostgreSQL database on Render, populating it with our knowledge, Dockerizing our FastAPI utility, and eventually deploying it to a Render Internet Utility.<\/p>\n<h2 class=\"wp-block-heading\">Desk of Contents<\/h2>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\"><a rel=\"nofollow\" target=\"_blank\" href=\"#deploy-database\" data-type=\"internal\" data-id=\"#deploy-database\">Deploying a PostgreSQL database on Render<\/a><\/li>\n<li class=\"wp-block-list-item\"><a rel=\"nofollow\" target=\"_blank\" href=\"#deploy-fastapi\" data-type=\"internal\" data-id=\"#deploy-fastapi\">Deploying a FastAPI app as a Render Internet Utility<\/a><br \/>\u2013 Dockerizing our utility<br \/>\u2013 Pushing Docker Picture to DockerHub<br \/>\u2013 Pulling from DockerHub to Render<\/li>\n<\/ol>\n<h2 class=\"wp-block-heading\">Tooling Used<\/h2>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Render<\/li>\n<li class=\"wp-block-list-item\">Docker Desktop<\/li>\n<li class=\"wp-block-list-item\">Docker Hub<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\" id=\"deploy-database\">Deploying on Render<\/h2>\n<p class=\"wp-block-paragraph\">Now we now have a PostgreSQL database and a FastAPI utility that work regionally, and it\u2019s time to deploy on a cloud service that may be accessed by a front-end utility or finish person (by way of Swagger). For this challenge, we\u2019ll use Render; Render is a cloud platform that, for small initiatives, provides a extra simple setup expertise than bigger cloud suppliers like AWS and Azure.<\/p>\n<p class=\"wp-block-paragraph\">To get began, navigate to <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/render.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Render <\/a>and create a brand new account, then you&#8217;ll be able to create a brand new challenge by choosing the \u2018New Undertaking\u2019 button proven beneath. Word, as of the time of this writing, Render has a trial interval that ought to let you observe alongside at zero price for the primary month. We&#8217;re calling this challenge fastapi-test, we then navigate into that challenge after it\u2019s created.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-134.png\" alt=\"\" class=\"wp-image-609082\"\/><figcaption class=\"wp-element-caption\">Determine 2: New Undertaking in Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Every challenge accommodates the whole lot required for that challenge to work in a self-contained setting. On this case, we&#8217;d like two elements: a database and an internet server for our FastAPI utility. Let\u2019s begin with creating our Database.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-135.png\" alt=\"\" class=\"wp-image-609084\"\/><figcaption class=\"wp-element-caption\">Determine 3: FastAPI Undertaking<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">That is quite simple, we choose \u2018Create New Service\u2019 as proven in Determine 3 after which choose \u2018Postgres\u2019. We\u2019re then navigated to the sector proven in Determine 4 to arrange the database. We identify our database \u201cfastapi-database\u201d and choose the free tier to get began. Render solely permits you to use the free tier database for a restricted time, however it is going to be tremendous for this instance, and in case you wanted to keep up a database long run, the pricing may be very affordable.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-136.png\" alt=\"\" class=\"wp-image-609085\"\/><figcaption class=\"wp-element-caption\">Determine 4: Postgres setup on Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">After inputting our database data and choosing \u2018Create\u2019 it can take a minute to arrange the database, and also you\u2019ll then be introduced with the display screen proven in Determine 5. We\u2019ll save the Inner Database URL + Exterior Database URL variables in our\u00a0.env file, as we\u2019ll want these to attach from our FastAPI utility. We are able to then check our connection to the database utilizing the Exterior Database URL variable(connecting from our native machine is exterior the Render Atmosphere) and create the tables from our native machine earlier than transferring on to organising our FastAPI utility.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-137.png\" alt=\"\" class=\"wp-image-609086\"\/><figcaption class=\"wp-element-caption\">Determine 5: Render database credentials<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">We then run our check database connection script, which makes an attempt to connect with our database by utilizing the External_Database_Url variable because the connection string and create a check desk. Word that our External_Database_Url is our full connection string for the database, so we will cross this as our single enter. A profitable run ought to lead to a printout as proven in Determine 6.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-138.png\" alt=\"\" class=\"wp-image-609087\"\/><figcaption class=\"wp-element-caption\">Determine 6: Profitable database connection from our native machine<\/figcaption><\/figure>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker, Session\nfrom sqlalchemy.ext.declarative import declarative_base\nimport os\nfrom dotenv import load_dotenv\nfrom utils.db_handler import DatabaseHandler\nimport pandas as pd\nimport uuid\nimport sys\nfrom sqlalchemy.exc import OperationalError\nimport psycopg2\n\n# Load setting variables from .env file (override=True reloads modified values)\nload_dotenv(override=True)\n# loaidng exterior database URL\ndatabase_url = os.environ.get(\"External_Database_Url\")\nif not database_url:\n    print(\"\u274c External_Database_Url not present in setting variables\")\n    print(\"Please examine your .env file accommodates: External_Database_Url=your_render_postgres_url\")\n    sys.exit(1)\nprint(f\"Database URL loaded: {database_url[:50]}...\")\n# Parse the database URL to extract elements for testing\nfrom urllib.parse import urlparse\nimport socket\ndef parse_database_url(url):\n    \"\"\"Parse database URL to extract connection elements\"\"\"\n    parsed = urlparse(url)\n    return {\n        'host': parsed.hostname,\n        'port': parsed.port or 5432,\n        'database': parsed.path.lstrip('\/'),\n        'username': parsed.username,\n        'password': parsed.password\n    }\ndb_params = parse_database_url(database_url)\ndef test_network_connectivity():\n    \"\"\"Take a look at community connectivity to Render PostgreSQL endpoint\"\"\"\n    print(\"n=== Community Connectivity Exams ===\")\n    # 1. Take a look at DNS decision\n    strive:\n        ip_address = socket.gethostbyname(db_params['host'])\n        print(f\"\u2705 DNS Decision profitable\")\n    besides socket.gaierror as e:\n        print(f\"\u274c DNS Decision failed: {e}\")\n        return False\n    \n    # 2. Take a look at port connectivity\n    strive:\n        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        sock.settimeout(10)  # 10 second timeout\n        end result = sock.connect_ex((db_params['host'], int(db_params['port'])))\n        sock.shut()\n        \n        if end result == 0:\n            print(f\"\u2705 Port {db_params['port']} is accessible\")\n            return True\n        else:\n            print(f\"\u274c Port {db_params['port']} is NOT accessible\")\n            print(\"   This would possibly point out a community connectivity challenge\")\n            return False\n    besides Exception as e:\n        print(f\"\u274c Port connectivity check failed: {e}\")\n        return False\n# Run connectivity checks\nnetwork_ok = test_network_connectivity()\nif not network_ok:\n    print(\"n\ud83d\udd0d TROUBLESHOOTING STEPS:\")\n    print(\"1. Verify your web connection\")\n    print(\"2. Confirm the Render PostgreSQL URL is right\")\n    print(\"3. Guarantee your Render PostgreSQL occasion is energetic\")\n    print(\"4. Verify if there are any Render service outages\")\n    sys.exit(1)\nprint(\"n=== Trying Database Connection ===\")\n# hook up with the database utilizing psycopg2\nstrive:\n    conn = psycopg2.join(\n            host=db_params['host'],\n            database=db_params['database'],\n            person=db_params['username'],\n            password=db_params['password'],\n            port=db_params['port'],\n            connect_timeout=30  # 30 second timeout\n        )\n    \n    # If the connection is profitable, you'll be able to carry out database operations\n    cursor = conn.cursor()\n    \n    # Instance: Execute a easy question\n    cursor.execute(\"SELECT model();\")\n    db_version = cursor.fetchone()\n    print(f\"\u2705 PostgreSQL Database Model: {db_version[0]}\")\n    \n    # Take a look at making a easy desk to confirm permissions\n    cursor.execute(\"CREATE TABLE IF NOT EXISTS connection_test (id SERIAL PRIMARY KEY, test_time TIMESTAMP DEFAULT NOW());\")\n    conn.commit()\n    print(\"\u2705 Database permissions verified - can create tables\")\n    \n    cursor.shut()\n    conn.shut()\n    print(\"\u2705 psycopg2 connection profitable!\")\n    \nbesides psycopg2.OperationalError as e:\n    print(f\"\u274c Database connection failed: {e}\")\n    if \"timeout\" in str(e).decrease():\n        print(\"n\ud83d\udd0d TIMEOUT TROUBLESHOOTING:\")\n        print(\"- Verify your web connection\")\n        print(\"- Confirm the Render PostgreSQL URL is right\")\n        print(\"- Verify if Render service is experiencing points\")\n    elif \"authentication\" in str(e).decrease():\n        print(\"n\ud83d\udd0d AUTHENTICATION TROUBLESHOOTING:\")\n        print(\"- Confirm the database URL accommodates right credentials\")\n        print(\"- Verify in case your Render PostgreSQL service is energetic\")\n        print(\"- Make sure the database URL hasn't expired or modified\")\n    sys.exit(1)\nbesides Exception as e:\n    print(f\"\u274c Sudden error: {e}\")\n    sys.exit(1)\n# If we get right here, connection was profitable, so exit the check\nprint(f\"n\u2705 All checks handed! Render PostgreSQL connection is working.\")\nprint(f\"\u2705 Related to database: {db_params['database']}\")\nprint(\"\u2705 Prepared to be used in your utility!\")\n<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Loading Database<\/h2>\n<p class=\"wp-block-paragraph\">Now that we\u2019ve verified that we will hook up with our database from our native machine, it\u2019s time to arrange our database tables and populate them. To load our database, we\u2019ll use our src\/load_database.py file, which we beforehand walked by way of the person items of this script at first of this text, so we received\u2019t go into additional element on it right here. The one notable factors are that we\u2019re once more utilizing our External_Database_Url as our connection string, after which on the finish, we\u2019re utilizing the test_table perform that we\u2019ve outlined as a part of our DatabaseHandler class. This perform makes an attempt to connect with the desk identify handed to it and returns the variety of rows in that desk.<\/p>\n<p class=\"wp-block-paragraph\">Operating this script ought to lead to an output as proven in Determine 11, the place every of the tables was created, after which on the finish we recheck that we will return knowledge from them and present that the output rows match the enter rows.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-139.png\" alt=\"\" class=\"wp-image-609088\"\/><figcaption class=\"wp-element-caption\">Determine 7: Database Efficiently Populated<\/figcaption><\/figure>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker, Session\nfrom sqlalchemy.ext.declarative import declarative_base\nimport os\nfrom dotenv import load_dotenv\nfrom utils.db_handler import DatabaseHandler\nimport pandas as pd\nimport uuid\nimport sys\nfrom sqlalchemy.exc import OperationalError\nimport psycopg2\n\n# Load setting variables from .env file\nload_dotenv(override=True)\n\n# Assemble PostgreSQL connection URL for Render\nURL_database = os.environ.get(\"External_Database_Url\")\n\n# Initialize DatabaseHandler with the constructed URL\nengine = DatabaseHandler(URL_database)\n\n# loading preliminary person knowledge\nusers_df = pd.read_csv(\"Knowledge\/steam_users.csv\")\ngames_df = pd.read_csv(\"Knowledge\/steam_games.csv\")\nuser_games_df = pd.read_csv(\"Knowledge\/steam_user_games.csv\")\nuser_recommendations_df = pd.read_csv(\"Knowledge\/user_recommendations.csv\")\ngame_tags_df = pd.read_csv(\"Knowledge\/steam_game_tags.csv\")\n\n\n# Defining queries to create tables\nuser_table_creation_query = \"\"\"CREATE TABLE IF NOT EXISTS customers (\n    id UUID PRIMARY KEY,\n    username VARCHAR(255) UNIQUE NOT NULL,\n    password VARCHAR(255) NOT NULL,\n    e mail VARCHAR(255) NOT NULL,\n    function VARCHAR(50) NOT NULL\n    )\n    \"\"\"\ngame_table_creation_query = \"\"\"CREATE TABLE IF NOT EXISTS video games (\n    id UUID PRIMARY KEY,\n    appid VARCHAR(255) UNIQUE NOT NULL,\n    identify VARCHAR(255) NOT NULL,\n    kind VARCHAR(255),\n    is_free BOOLEAN DEFAULT FALSE,\n    short_description TEXT,\n    detailed_description TEXT,\n    builders VARCHAR(255),\n    publishers VARCHAR(255),\n    value VARCHAR(255),\n    genres VARCHAR(255),\n    classes VARCHAR(255),\n    release_date VARCHAR(255),\n    platforms TEXT,\n    metacritic_score FLOAT,\n    suggestions INTEGER\n    )\n    \"\"\"\n\nuser_games_query = \"\"\"CREATE TABLE IF NOT EXISTS user_games (\n    id UUID PRIMARY KEY,\n    username VARCHAR(255) NOT NULL,\n    appid VARCHAR(255) NOT NULL,\n    shelf VARCHAR(50) DEFAULT 'Wish_List',\n    ranking FLOAT DEFAULT 0.0,\n    evaluate TEXT\n    )\n    \"\"\"\nrecommendation_table_creation_query = \"\"\"CREATE TABLE IF NOT EXISTS user_recommendations (\n    id UUID PRIMARY KEY,\n    username VARCHAR(255),\n    appid VARCHAR(255),\n    similarity FLOAT\n    )\n    \"\"\"\n\ngame_tags_creation_query = \"\"\"CREATE TABLE IF NOT EXISTS game_tags (\n    id UUID PRIMARY KEY,\n    appid VARCHAR(255) NOT NULL,\n    class VARCHAR(255) NOT NULL\n    )\n    \"\"\"\n\n# Operating queries to create tables\nengine.delete_table('user_recommendations')\nengine.delete_table('user_games')\nengine.delete_table('game_tags')\nengine.delete_table('video games')\nengine.delete_table('customers')\n\n# Create tables\nengine.create_table(user_table_creation_query)\nengine.create_table(game_table_creation_query)\nengine.create_table(user_games_query)\nengine.create_table(recommendation_table_creation_query)\nengine.create_table(game_tags_creation_query)\n\n# Making certain every row of every dataframe has a novel ID\nif 'id' not in users_df.columns:\n    users_df['id'] = [str(uuid.uuid4()) for _ in range(len(users_df))]\nif 'id' not in games_df.columns:\n    games_df['id'] = [str(uuid.uuid4()) for _ in range(len(games_df))]\nif 'id' not in user_games_df.columns:\n    user_games_df['id'] = [str(uuid.uuid4()) for _ in range(len(user_games_df))]\nif 'id' not in user_recommendations_df.columns:\n    user_recommendations_df['id'] = [str(uuid.uuid4()) for _ in range(len(user_recommendations_df))]\nif 'id' not in game_tags_df.columns:\n    game_tags_df['id'] = [str(uuid.uuid4()) for _ in range(len(game_tags_df))]\n\n# Populates the 4 tables with knowledge from the dataframes\nengine.populate_table_dynamic(users_df, 'customers')\nengine.populate_table_dynamic(games_df, 'video games')\nengine.populate_table_dynamic(user_games_df, 'user_games')\nengine.populate_table_dynamic(user_recommendations_df, 'user_recommendations')\nengine.populate_table_dynamic(game_tags_df, 'game_tags')\n\n# Testing if the tables have been created and populated appropriately\nprint(engine.test_table('customers'))\nprint(engine.test_table('video games'))\nprint(engine.test_table('user_games'))\nprint(engine.test_table('user_recommendations'))\nprint(engine.test_table('game_tags'))<\/code><\/pre>\n<h2 class=\"wp-block-heading\" id=\"deploy-fastapi\">Deploying a FastAPI Utility on Render<\/h2>\n<p class=\"wp-block-paragraph\">We now have the primary half of our challenge deployed on render, and it\u2019s time to arrange our FastAPI utility. To do that, we\u2019re going to make use of Render\u2019s Internet Utility internet hosting service, which can permit us to deploy our FastAPI App as an internet utility that may be accessed by exterior companies. If we needed to construct a full-stack utility, we might then permit our entrance finish to ship requests to the FastAPI utility on Render and return knowledge to the person. Nonetheless, as a result of we\u2019re not involved in constructing a front-end element at the moment, we\u2019ll as an alternative work together with our App by way of the Swagger docs.<\/p>\n<h2 class=\"wp-block-heading\">Containerizing our Utility with Docker<\/h2>\n<p class=\"wp-block-paragraph\">We\u2019ve arrange our FastAPI challenge in a neighborhood setting, however now we have to switch it, with all of the code, dependencies, and environmental variables, to a container on Render. This may very well be a frightening problem. Fortuitously, Docker handles all of the sophisticated items and permits us to do exactly that with a easy configuration file and a few instructions. For individuals who haven\u2019t used Docker, there&#8217;s a nice tutorial <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=b0HMimUb4f0\" rel=\"noreferrer noopener\" target=\"_blank\">right here<\/a>. The temporary overview is that Docker is a software that simplifies the method of deploying and managing purposes by permitting us to bundle our utility with all its dependencies as a picture after which deploy that picture to a service like Render. On this challenge, we use DockerHub as our picture repository, which serves as a central version-controlled storage space for our picture, which we will then pull into Render.<\/p>\n<p class=\"wp-block-paragraph\">Our total circulation for this challenge may be considered like this FastAPI app operating regionally \u2192 A \u2018Snapshot\u2019 is taken with Docker and saved as a Docker Picture \u2192 That Picture is pushed to DockerHub \u2192 Render pulls this picture and makes use of it to spin up a Container that runs the appliance on a Render Server. Getting began with this course of, which we\u2019ll stroll by way of subsequent, requires having Docker Desktop put in. Docker has a simple set up course of which you may get began on right here: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.docker.com\/merchandise\/docker-desktop\/<\/a><\/p>\n<p class=\"wp-block-paragraph\">Moreover, in case you don\u2019t have one already, you\u2019ll want a Docker Hub account as it will function the repository to save lots of Docker Photographs to after which Pull them into Render. You may create a Docker Hub right here: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/hub.docker.com\/\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/hub.docker.com\/<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">Constructing a Docker Picture<\/h2>\n<p class=\"wp-block-paragraph\">To create a Docker Picture for our challenge, first be sure that Docker Desktop is operating; if it isn\u2019t, you\u2019ll seemingly get an error when attempting to create a Docker picture. To make sure it\u2019s operating, open the Docker Desktop utility out of your search bar or desktop, click on on the three dots within the backside left as proven beneath, and make sure you see the Inexperienced dot adopted by \u2018Docker Desktop is operating\u2019.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-140.png\" alt=\"\" class=\"wp-image-609089\"\/><figcaption class=\"wp-element-caption\">Determine 8: Docker Desktop operating<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Subsequent, we have to inform Docker how you can construct our picture, which is finished by defining a Dockerfile. Our Dockerfile may be seen in Determine 9. We reserve it in our top-level listing, and it gives the directions that inform Docker how you can bundle our utility into a picture that may be deployed on a special piece of {hardware}. Let\u2019s stroll by way of this file to know what it\u2019s doing.<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">FROM: Selecting Base Picture: The primary line in our Dockerfile specifies what base picture we need to use to then prolong for our utility. On this case, we&#8217;re utilizing the python:3.13-slim-bullseye picture, which is a light-weight Debian-based picture that can function the bottom for our utility.<\/li>\n<li class=\"wp-block-list-item\">WORKDIR: Altering Work Listing: Right here we&#8217;re setting the default listing inside our container to \/app<\/li>\n<li class=\"wp-block-list-item\">RUN: Checking for updates to system dependencies<\/li>\n<li class=\"wp-block-list-item\">COPY: Coping necessities.txt file, it\u2019s vital that necessities.txt is updated and accommodates all libraries required for the challenge, or the Picture received\u2019t run appropriately after we attempt to spin it up<\/li>\n<li class=\"wp-block-list-item\">RUN: Putting in our necessities.txt file<\/li>\n<li class=\"wp-block-list-item\">COPY: Copy our complete challenge from our native listing to \/app, which we created in step 2<\/li>\n<li class=\"wp-block-list-item\">RUN: Making a logs listing at \/app\/logs<\/li>\n<li class=\"wp-block-list-item\">EXPOSE: Doc that the port we\u2019ll be exposing is port 8000<\/li>\n<li class=\"wp-block-list-item\">ENV: Units our Python path to \/app<\/li>\n<li class=\"wp-block-list-item\">CMD: Runs our FastAPI app utilizing Uvicorn, units our app to the one outlined in src.essential:app, runs our app on port 8000<\/li>\n<\/ol>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-141.png\" alt=\"\" class=\"wp-image-609091\"\/><figcaption class=\"wp-element-caption\">Determine 9: Dockerfile<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">With our Dockerfile outlined, we now have a set of directions that we may give to Docker to containerize our utility into a picture that we will then push to Docker Hub. We are able to now do that with a few instructions from our VS Code terminal, proven beneath. Every of those traces must be run individually within the VS Code terminal from the highest listing of your challenge.<\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">First, we construct our Docker picture, which can seemingly take a minute or two. On this case, we&#8217;re naming our picture \u2018recommendersystem\u2019<\/li>\n<li class=\"wp-block-list-item\">Subsequent, we tag our picture, the syntax right here is image_name user_name\/docker_hub_folder:image_name_on_dockerhub<\/li>\n<li class=\"wp-block-list-item\">Lastly, we push our picture to Dockerhub once more specifying the user_name\/docker_hub_folder:image_name_on_dockerhub<\/li>\n<\/ol>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">docker construct -t recommendersystem .\ndocker tag recommendersystem seelucas\/fastapi_tutorial:fastapi_on_render\ndocker push seelucas\/fastapi_tutorial:fastapi_on_render<\/code><\/pre>\n<p class=\"wp-block-paragraph\">After that is finished, we must always be capable of log in to DockerHub, navigate to our challenge, and see that we now have a picture whose identify matches what we gave it within the earlier 3 instructions, on this case, fastapi_on_render.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-142.png\" alt=\"\" class=\"wp-image-609092\"\/><figcaption class=\"wp-element-caption\">Determine 10: Docker Picture on Dockerhub<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Pulling Docker Picture to Render<\/h2>\n<p class=\"wp-block-paragraph\">Now we now have our Docker Picture on DockerHub, and it\u2019s time to deploy that Picture on Render. This may be finished by navigating to the identical challenge that we created our database in, \u201cfastapi-test\u201d, choosing \u201cNew\u201d, within the high proper, after which choosing \u201cInternet Service\u201d as our FastAPI app can be deployed as a Internet Utility.<\/p>\n<p class=\"wp-block-paragraph\">As a result of we&#8217;re deploying our picture from Dockerhub, we specify that our Supply Code is an Present Picture, and as proven in Determine 11, we paste the Dockerhub Listing path to the Picture we need to deploy into \u2018Picture URL\u2019 in Render. We then get a notification that this can be a non-public picture, which suggests we\u2019ll must create a Dockerhub Entry token that we will then use to securely pull the picture from DockerHub into Render.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-143.png\" alt=\"\" class=\"wp-image-609093\"\/><figcaption class=\"wp-element-caption\">Determine 11: Docker Picture on Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Fortuitously, making a DockerHub Entry token is easy; we navigate to our DockerHub account -&gt; Settings \u2192 Private Entry token. The display screen ought to appear to be Determine 12. we offer an entry token identify, expiration date, and permissions. Since we\u2019re pulling the picture into Render, we solely want learn entry relatively than write or delete, so we choose that.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-144.png\" alt=\"\" class=\"wp-image-609094\"\/><figcaption class=\"wp-element-caption\">Determine 12: Creating private entry token for Dockerhub<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Lastly, choosing \u2018Generate\u2019 will generate our token, which we then want to repeat over to render and enter as proven in Determine 13.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-145.png\" alt=\"\" class=\"wp-image-609095\"\/><figcaption class=\"wp-element-caption\">Determine 13: Docker credentials on Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">As soon as we\u2019ve chosen \u2018Add Credential\u2019 as proven above, it can then load for a minute because the credentials are saved. We\u2019ll then be taken again to the earlier display screen, the place we will choose our credentials to make use of to connect with DockerHub. On this case, we\u2019ll use the tutorial credentials we simply created and choose Join. We&#8217;ll then have established a connection that we will use to tug our Docker Picture from DockerHub to Render for Deployment.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-146.png\" alt=\"\" class=\"wp-image-609096\"\/><figcaption class=\"wp-element-caption\">Determine 14: Render Internet Service with Legitimate Credentials<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">On the following web page, we proceed with organising our Render Internet applicaiton by choosing the free choice after which importantly, on Environmental Variables, we copy and paste our\u00a0.env file. Whereas we don\u2019t use all of the variables on this file, we do use the \u2018Internal_Database_Url\u2019, which is the URL that FastAPI will search for in our essential.py file. With out this, we received\u2019t be capable of hook up with our database, so it\u2019s vital that we offer this. Word: for testing, we beforehand used the \u2018External_Database_Url\u2019 as a result of we have been operating the script from our native machine, which is exterior to our Render setting; nevertheless, right here each the Database and Internet Server are in the identical Render setting, so we use the Internal_Database_Url in essential.py.<\/p>\n<p class=\"wp-block-paragraph\">After coming into our environmental variables, we then select \u2018Deploy Internet Service\u2019.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-147.png\" alt=\"\" class=\"wp-image-609097\"\/><figcaption class=\"wp-element-caption\">Determine 15: Environmental Variables Added to Render Internet App<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The service will take a few minutes to deploy, however then it is best to get a notification like beneath that the service has deployed with a render hyperlink on high that we will entry at.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-148.png\" alt=\"\" class=\"wp-image-609098\"\/><figcaption class=\"wp-element-caption\">Determine 16: Internet Utility deploying on Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Navigating to this hyperlink will take us to the Hiya World technique, if we add\/docs to the top of it, we\u2019ll be taken to the swagger docs in Determine 17. Right here we will check and guarantee our FastAPI Internet Utility is linked to our database by utilizing the Fetch All Customers technique. We are able to see beneath that this does certainly return knowledge.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-149.png\" alt=\"\" class=\"wp-image-609099\"\/><figcaption class=\"wp-element-caption\">Determine 17: Swagger Docs for FastAPI on Render<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Lastly, we need to examine if our person suggestions system is dynamically updating. In your earlier API name, we will see that there\u2019s a person \u2018user_username\u2019 in our database. Utilizing the Fetch Really useful Recreation technique with this username, we will see the highest match is appid = B08BHHRSPK.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-150.png\" alt=\"\" class=\"wp-image-609100\"\/><figcaption class=\"wp-element-caption\">Determine 18: Pre-Replace person suggestion<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">We replace our customers\u2019 favored video games by selecting a random one from our video games appid = B0BHTKGN7F, which seems to be \u2018The Elder Scrolls: Skyrim Boardgame\u2019, and leveraging our user_games POST technique.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-151.png\" alt=\"\" class=\"wp-image-609101\"\/><figcaption class=\"wp-element-caption\">Determine 19: Including a favored boardgame<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Including a sport to our person video games desk is meant to mechanically set off the recommender pipeline to rerun for that person and generate new suggestions. If we navigate to our console, we will see that it seems to have occurred as we get the brand new person suggestions generated message proven beneath.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-152.png\" alt=\"\" class=\"wp-image-609102\"\/><figcaption class=\"wp-element-caption\">Determine 20: Console Picture of Recommender pipeline Run<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">If we navigate again to our Swagger docs, we will strive the fetch suggestion technique once more, and we see in Determine 21 that we certainly do have a special checklist of suggestions than the one earlier than. Our Recommender Pipeline is now mechanically updating as customers add extra knowledge and is accessible past our native setting.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/07\/image-153.png\" alt=\"\" class=\"wp-image-609103\"\/><figcaption class=\"wp-element-caption\">Determine 21: really useful video games after similarity pipeline run<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Wrapping Up:<\/h2>\n<p class=\"wp-block-paragraph\">On this challenge, we\u2019ve proven how you can arrange and deploy a suggestion system leveraging a FastAPI interplay layer with a PostgreSQL database to generate clever board sport suggestions for our customers. There are additional steps we might take to make this method extra sturdy, like implementing a hybrid suggestion system as we achieve extra person knowledge or enabling person tagging to seize extra options. Moreover, though we didn\u2019t cowl it, we did make the most of a GitHub workflow to rebuild and push our Docker picture each time there\u2019s a brand new replace to our essential department, and this code is on the market in\u00a0.github\/workflows. This helped to tremendously speedup growth as we didn\u2019t should manually rebuild our Docker picture each time we made a small change.<\/p>\n<p class=\"wp-block-paragraph\">I hope you loved studying and that this helps you construct and deploy your initiatives with FastAPI.<\/p>\n<p class=\"wp-block-paragraph\">LinkedIn: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.linkedin.com\/in\/lucas-see-6b439188\/\" rel=\"noreferrer noopener\" target=\"_blank\">https:\/\/www.linkedin.com\/in\/lucas-see-6b439188\/<\/a><\/p>\n<p class=\"wp-block-paragraph\">E mail: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/towardsdatascience.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"8efdebebe2edfdbfbccee9e3efe7e2a0ede1e3\">[email\u00a0protected]<\/a><\/p>\n<p class=\"wp-block-paragraph\"><strong>Figures<\/strong>: All photographs, until in any other case famous, are by the writer.<\/p>\n<p class=\"wp-block-paragraph\"><strong>Hyperlinks:<\/strong><\/p>\n<ol class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Github Repository for Undertaking: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/pinstripezebra\/recommender_system\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/pinstripezebra\/recommender_system<\/a><\/li>\n<li class=\"wp-block-list-item\">FastAPI Docs: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/fastapi.tiangolo.com\/tutorial\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/fastapi.tiangolo.com\/tutorial\/<\/a><\/li>\n<li class=\"wp-block-list-item\">Docker Tutorial: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=b0HMimUb4f0\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.youtube.com\/watch?v=b0HMimUb4f0<\/a><\/li>\n<li class=\"wp-block-list-item\">Docker Desktop Obtain: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.youtube.com\/watch?v=b0HMimUb4f0\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.youtube.com\/watch?v=b0HMimUb4f0<\/a><\/li>\n<li class=\"wp-block-list-item\">Docker Hub: <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/hub.docker.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/hub.docker.com\/<\/a><\/li>\n<\/ol>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Getting Began In half 1 we walked by way of the method of organising a board sport suggestion system leveraging FastAPI and PostgreSQL. In Half 2 we proceed this challenge and present how you can deploy this challenge to a cloud service, on this case Render, to make it accessible to customers. To make this [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":7036,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[475,3170,89,5548,5546,2548,5547,849,180],"class_list":["post-7034","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-machine-learning","tag-building","tag-fastapi","tag-game","tag-part2","tag-postgresql","tag-recommender","tag-render","tag-system","tag-video"],"_links":{"self":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/7034","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7034"}],"version-history":[{"count":1,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/7034\/revisions"}],"predecessor-version":[{"id":7035,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/7034\/revisions\/7035"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/media\/7036"}],"wp:attachment":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7034"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7034"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7034"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- This website is optimized by Airlift. Learn more: https://airlift.net. Template:. Learn more: https://airlift.net. Template: 69d9690a190636c2e0989534. Config Timestamp: 2026-04-10 21:18:02 UTC, Cached Timestamp: 2026-05-06 21:29:01 UTC -->