FastAPI är ett kraftfullt ramverk för att bygga webbtjänster med hjälp av Python, och det ger utvecklare en rad funktioner för att hantera parametrar i URL-vägar. När vi arbetar med dynamiska parametrar, kan vi stöta på olika scenarier som involverar både vägparametrar och frågeparametrar. Genom att utnyttja funktioner som typ-annoteringar och inbyggda verktyg som Path, kan vi effektivisera vår API-utveckling och säkerställa korrekt hantering av inkommande data.

Först och främst kan vi observera hur FastAPI hanterar dynamiska vägar genom att använda URL-parametrar. I ett enkelt exempel, om vi definierar en väg som /car/{id}, där id är en dynamisk parameter, kan vi förvänta oss att den parametriserade vägen tar emot vilken typ av data som helst, exempelvis en sträng. Om vi skapar en route med en variabel av typen int för id, som i /carh/{id}, kommer FastAPI att försöka tolka värdet efter {id} som ett heltal. Om värdet inte är ett heltal, kommer servern att returnera ett 422-fel, vilket indikerar att datan inte kunde behandlas, samt beskriva exakt var felet inträffade.

Det är också viktigt att förstå hur ordningen på vägdefinitionerna påverkar vilket endpoint som matchas. Om vi har en väg som /user/{id} och en annan som /user/me, där den senare ska visa information om den nuvarande användaren, kan ordningen vara avgörande. Om /user/me definieras före /user/{id}, kan den första vägen inte fånga en förfrågan om /user/me, eftersom FastAPI matchar den dynamiska vägen först. Därmed måste vi alltid säkerställa att statiska vägar som /user/me kommer före de dynamiska vägarna som /user/{id}.

En annan viktig aspekt är användningen av enums för att begränsa parametrarnas möjliga värden. Anta att vi vill skapa en väg som accepterar en parametrar som representerar kontotypen, där värdet kan vara "free" eller "pro". Genom att använda en Enum-klass definierar vi dessa värden och kan säkerställa att inga andra värden accepteras. På samma sätt kan vi använda verktyget Path för att införa ytterligare begränsningar på numeriska parametrar. Vi kan till exempel kräva att ett heltal, som antalet månader för ett abonnemang, ligger inom ett specifikt intervall, exempelvis mellan 3 och 12 månader. Genom att använda dessa funktioner kan vi skapa robusta och säkra API-endpoints.

När vi har förstått hur man hanterar vägar och parametrar är nästa steg att arbeta med frågeparametrar. Frågeparametrar är nyckel-värde-par som kan läggas till en URL efter ett frågetecken, till exempel ?min_price=2000&max_price=4000. Dessa används ofta för att filtrera eller sortera data, eller för att paginera stora mängder information. I FastAPI kan vi behandla dessa frågeparametrar på samma sätt som vägparametrar, vilket innebär att vi kan definiera standardvärden för dem och även tillämpa validering för att säkerställa att inkommande data uppfyller vissa krav. Om vi exempelvis skapar en endpoint för att lista bilar inom ett visst prisintervall, kan vi definiera två frågeparametrar, min_price och max_price, med standardvärden för att säkerställa att vi alltid får ett resultat inom ett rimligt intervall.

Det är också värt att påpeka att FastAPI gör det möjligt att lägga till ytterligare validering i vägar, något som kan vara avgörande för att förhindra ogiltiga eller osäkra data från att passera genom API:et. Ett exempel är användningen av Path-verktyget för att lägga till begränsningar på vägparametrar. Med ge (greater than or equal) och le (less than or equal) kan vi definiera att en parameter måste vara ett tal inom ett visst intervall, vilket gör det lättare att hantera användarinmatningar och säkerställa dataintegritet.

Det är också viktigt att förstå att FastAPI inte bara validerar typbaserat utan också ger detaljerad feedback när något går fel. Om en användare skickar in en felaktig parameter, som ett icke-heltal när ett heltal förväntas, kommer systemet att returnera ett felmeddelande som förklarar exakt vad som är fel. Det gör det enkelt för utvecklare och användare att snabbt rätta till sina förfrågningar och säkerställa korrekt dataflöde.

För att sammanfatta, genom att använda FastAPI:s inbyggda funktioner för väg- och frågeparametrar, samt genom att utnyttja typ-annoteringar och validering, kan vi bygga kraftfulla, flexibla och säkra API:er som är både användarvänliga och robusta nog för att hantera komplexa datainteraktioner. När man utvecklar applikationer där användarinteraktioner sker via webben är det avgörande att förstå hur dessa parametrar fungerar för att kunna skapa en effektiv och felfri tjänst.

Hur bygger man ett autentiseringssystem med FastAPI och en användardatabas?

När man bygger ett autentiseringssystem från grunden med FastAPI, är det viktigt att förstå hur olika delar av systemet samverkar för att skapa en säker och funktionell användarupplevelse. Här är en översikt av hur man implementerar användarregistrering, inloggning och skyddade rutter i ett FastAPI-baserat system.

Först och främst, skapa en instans av APIRouter och en anpassad klass för hantering av autentisering. Den här klassen kommer att hjälpa till att skapa och verifiera användartokens. Ett vanligt tillvägagångssätt är att använda ett JSON-dokument (som en ersättning för en riktig databas) för att lagra användardata under utvecklingens tidiga faser. I det här exemplet använder vi en fil som heter users.json, där vi lagrar en lista med användardata (ID, användarnamn och hashlös lösenord).

I registreringsrouten, /register, mottar servern användardata och omvandlar den via en Pydantic-modell. Det är viktigt att här validera användarnamnet för att säkerställa att det inte redan är taget, och därefter hasha lösenordet innan det sparas i "databasen". Den här metoden gör att känslig information, som användarens lösenord, inte lagras i klartext. I stället lagras det som ett hashvärde som inte går att återskapa.

När en användare försöker registrera sig, laddas innehållet i users.json och jämförs med användarnamnet som skickas i förfrågan. Om användarnamnet redan är upptaget, skickas ett HTTP 409-fel (konflikt) tillbaka till användaren. Om det är ledigt, hashas lösenordet och användarens information sparas i JSON-filen med hjälp av en unik UUID för att identifiera varje användare.

Vid inloggning används en liknande process. Inloggningsrouten, /login, kontrollerar att både användarnamn och lösenord matchar mot de lagrade uppgifterna i filen. Vid korrekt inloggning genereras en JWT-token (JSON Web Token) som skickas tillbaka till användaren. Det är en säkerhetsmetod som används för att autentisera användare vid framtida begärningar. En säkerhetspraxis här är att aldrig avslöja vilken del av autentisering som misslyckades (om det är användarnamnet eller lösenordet som är fel), utan att helt enkelt ge ett generellt felmeddelande vid felaktig inloggning.

För att skydda specifika rutter och säkerställa att endast inloggade användare får åtkomst, använder vi FastAPIs kraftfulla beroendeinjektionssystem. Genom att använda en auth_wrapper-funktion kan vi implementera en kontroll där användaren måste skicka med sin JWT-token i headern för att få åtkomst till skyddade rutter. Detta görs enkelt genom att skapa en ny GET-rutt, /list, där endast autentiserade användare kan lista alla användare.

Det är också viktigt att förstå att detta system inte är lämpligt för produktion. I en riktig produktionsmiljö skulle du använda en riktig databas (som MongoDB) istället för en JSON-fil, och det skulle finnas fler säkerhetsmekanismer för att skydda användardata och tokens. För att göra detta mer robust, kan man exempelvis lägga till fler funktioner som att skapa, uppdatera och ta bort användare, samt mer avancerad tokenhantering.

Det är också avgörande att säkerställa att de data som lagras är skyddade genom att använda säkra lösenordshashalgoritmer och att säkerställa att JWT-token inte är sårbara för olika typer av attacker. I det här fallet används en enkel metod för att demonstrera autentisering och kan förbättras i en riktig applikation.

Slutligen, även om den här metoden för autentisering är relativt enkel att implementera, måste du som utvecklare vara medveten om att autentisering och auktorisering är komplexa ämnen som kräver noggrann planering och korrekt implementering för att säkerställa både användarens integritet och systemets säkerhet.

Hur man bygger en API för att hantera begagnade bilar med FastAPI

Att manuellt testa API-endpunkterna som du ska implementera är ett bra sätt att förstå hur de fungerar i praktiken. För att börja, behöver vi först förstå den applikation vi ska utveckla och vad backend-systemet kommer att kräva.

Applikationen som vi ska bygga handlar om att skapa ett REST API-backend för att lagra och hämta data om begagnade bilar för ett fiktivt bilförsäljningsföretag. Den data som behövs för att beskriva en bil är relativt enkel men kan snabbt bli mer komplicerad när detaljer som motormodeller, interiörfärger, fjädringstyper och andra specifikationer tas med. För att börja kommer vi att hålla oss till en enkel CRUD-applikation, där bilens data begränsas till följande fält:

  • Brand: Märket på bilen (t.ex. Ford, Renault), representerat som en sträng

  • Make eller model: Till exempel Fiesta eller Clio, representerat som en sträng

  • Year: Tillverkningsåret, ett heltal inom ett rimligt spann (1970–2024)

  • Cm3: Motorns cylindervolym, ett heltal som relaterar till motorns effekt

  • kW: Motorns effekt i kW, ett heltal

  • Km: Hur många kilometer bilen har körts, ett heltal i hundratusental

  • Price: Pris i euro

  • Bild-URL: Ett valfritt fält som refererar till en bild på bilen

En viktig funktion för alla bilförsäljningswebbplatser är möjligheten att visa bilder av bilarna. För detta kommer vi att implementera en bilduppladdningstjänst via Cloudinary, en av de ledande tjänsterna för bildhantering och lagring.

För att lagra data ska vi använda en MongoDB-databas, där vi skapar en instans av Atlas och en samling för att lagra bilinformation. Vi börjar med att skapa en databas som heter carBackend och en samling kallad cars.

När databasen är uppsatt och ansluten, måste vi skapa en ny Python-miljö och installera de nödvändiga paketen. Här är de paket vi kommer att använda för vårt projekt:

  • fastapi: För att bygga vårt API

  • motor: För att ansluta till MongoDB

  • uvicorn: För att köra API-servern

  • pydantic-settings: För att hantera inställningar i Pydantic

Vi definierar sedan vår Pydantic-modell för att representera en bil, inklusive alla nödvändiga fält och valideringar. En av de största utmaningarna vid arbetet med MongoDB och FastAPI är hanteringen av ObjectID, som används som den primära nyckeln för varje dokument. För att enkelt kunna använda ObjectID i Pydantic-modellen omvandlas den till en sträng. För detta ändamål använder vi en alias-struktur i Pydantic, vilket gör att vi kan hantera MongoDB:s unika identifierare som ett vanligt strängfält.

Här är ett exempel på hur vi definierar vår bilmodell:

python
from pydantic import BaseModel, Field from typing import Optional from pydantic.class_validators import field_validator class CarModel(BaseModel):
id: Optional[str] = Field(alias="_id", default=None)
brand:
str make: str year: int cm3: int km: int price: int @field_validator("brand") def capitalize_brand(cls, v: str) -> str: return v.title() @field_validator("make")
def capitalize_make(cls, v: str) -> str:
return v.title()

Den här modellen definierar fälten som vi behöver för att beskriva en bil, och alla fält är validerade för att säkerställa att de följer de regler vi satt upp, som till exempel att årtalet måste vara mellan 1970 och 2024 och att priset måste vara ett positivt tal.

För att testa denna modell, kan vi skapa en instans av CarModel och skriva ut den i JSON-format för att säkerställa att allting fungerar korrekt.

När denna grundläggande modell är klar är det dags att skapa en modell för uppdatering av bilinformation. Eftersom bilar är ganska statiska objekt, kan vi anta att endast vissa fält kan ändras, exempelvis priset. För att göra detta mer flexibelt kan vi skapa en uppdateringsmodell där vissa fält är valfria och kan uppdateras vid behov.

python
class UpdateCarModel(BaseModel):
brand: Optional[str] make: Optional[str] year: Optional[int] cm3: Optional[int] km: Optional[int] price: Optional[int]

Den här modellen tillåter att uppdatera valfria fält, och det är viktigt att säkerställa att uppdateringar som görs är inom de definierade gränserna för varje fält. För en fullständig lösning måste vi även implementera funktioner för att ta bort bilar och för att hämta en lista med alla bilar i systemet.

Det är också viktigt att förstå att detta system är förhållandevis enkelt, och som projektet växer, kan fler funktioner och förbättringar behövas. Till exempel kan man överväga att implementera autentisering och auktorisering för att skydda API:et, samt mer avancerade funktioner som sökfilter och sorts funktioner för att underlätta användningen av bilförsäljningssystemet.

Hur man bygger en frontend-applikation med Vite, React och React Router

För att skapa en frontend-applikation med Vite och React, börjar du med att använda Node package manager (npm) för att generera ditt projekt. Första steget är att skapa en Vite React-applikation. Detta görs genom att öppna terminalen i din projektmapp, där backend-katalogen redan är skapad, och köra följande kommando:

bash
npm create vite@latest frontend-app -- --template react

När projektet är skapat, går du in i den nya frontend-app-katalogen och installerar de nödvändiga beroendena tillsammans med TailwindCSS:

bash
npm install -D tailwindcss postcss autoprefixer

Nästa steg är att initiera Tailwind-konfigurationen:

bash
npx tailwindcss init -p

Efter detta ska du konfigurera den genererade tailwind.config.js och Reacts index.css enligt den senaste dokumentationen från TailwindCSS. Din index.css bör endast innehålla följande importkommandon:

css
@tailwind base; @tailwind components; @tailwind utilities;

För att testa om Tailwind har konfigurerats korrekt, kan du göra en enkel förändring i App.jsx-filen och starta utvecklingsservern:

jsx
export default function App() {
return ( <h1 className="text-3xl font-bold"> Cars FARM </h1> ); }

När du uppdaterar din app bör du se en vit sida med texten "Cars FARM". Med en fungerande React-applikation och Tailwind på plats, är nästa steg att introducera React Router, en av de mest betydelsefulla tredjepartspaketen för React.

React Router: Navigering mellan sidor

Vid det här laget har du byggt en enkel applikation med en enda sida (SPA), men för att göra din applikation mer funktionell och dynamisk behöver du kunna hantera flera sidor baserat på användarens navigation. Här kommer React Router in. React Router är ett paket som gör det möjligt att definiera och hantera rutter i en React-applikation. Det tillåter dig att skapa flera sidor och visa dem beroende på den URL som användaren besöker.

Även om det finns andra alternativ för routing i React, som TanStack Router, är React Router det mest använda och väletablerade paketet. Version 6.4 av React Router innebär vissa stora förändringar men behåller de grundläggande funktionerna. Dessutom har React Router version 6.4 introducerat nya funktioner för att förenkla datahämtning och andra förbättringar som gör det till ett ännu mer kraftfullt verktyg.

Det grundläggande konceptet bakom React Router är att lyssna på URL-vägar (som /about eller /login) och visa komponenter beroende på vilken väg som är aktiv. Dessa komponenter motsvarar sidor, och layouten förblir densamma med vissa gemensamma element som navigation och footer.

Installera och konfigurera React Router

För att börja använda React Router i din applikation behöver du först installera paketet:

bash

När installationen är klar, ska du skapa en ny mapp som heter /pages i din /src-mapp och sedan skapa alla nödvändiga sidor som du vill använda i din applikation. Sidorna kommer att ha namn som Home.jsx, Cars.jsx, Login.jsx, NewCar.jsx, NotFound.jsx och SingleCar.jsx.

Exempel på en enkel komponent, Home.jsx, ser ut så här:

jsx
const Home = () => {
return ( <div>Home</div> ); }; export default Home;

Dessa sidor är i grunden vanliga React-komponenter, men eftersom de används för att representera olika delar av en SPA, kallas de ofta för "sidor".

Skapa en router och integrera den i applikationen

Nu när sidorna är skapade, är nästa steg att konfigurera routern. I React Router version 6.4 är det rekommenderat att använda createBrowserRouter för att hantera routing, då det stöder de nya funktionerna som dataladdning. För att konfigurera detta, behöver du skapa en layoutkomponent där dina sidor ska renderas. Skapa en ny mapp kallad /layouts och lägg till en RootLayout.jsx-fil.

jsx
const RootLayout = () => {
return ( <div>Root Layout</div> ); }; export default RootLayout;

I din App.jsx-fil ska du importera routerpaketets nödvändiga funktioner och de sidor du har skapat. Här är ett exempel på hur du kan implementera en router med createBrowserRouter:

jsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import RootLayout from './layouts/RootLayout';
import Home from './pages/Home'; import Cars from './pages/Cars'; import Login from './pages/Login'; const router = createBrowserRouter([ { path: "/", element: <RootLayout />, children: [ { path: "/", element: <Home />, }, { path: "/cars", element: <Cars />, }, { path: "/login", element: <Login />, } ], }, ]); function App() { return ( <RouterProvider router={router} /> ); } export default App;

Denna struktur ger en funktionell applikation där varje URL-väg renderar en specifik komponent, och layouten hålls konsekvent med gemensamma element som navigation och footer.

För att fortsätta utveckla applikationen kan du lägga till fler funktioner som autentisering, användarhantering och dataladdning. React Router gör det också möjligt att skapa dynamiska vägar för enskilda objekt, som en specifik bils sida baserat på ett ID. Detta kan göras med hjälp av :id i vägen, vilket gör att applikationen kan hämta och visa specifik data utan att ladda om sidan.

Vad är viktigt att förstå bortom det tekniska

Förutom att lära sig hur man implementerar och konfigurerar React Router, är det också avgörande att förstå vikten av att skapa en bra användarupplevelse genom smidig navigering och dataladdning. Att använda React Router effektivt innebär att designa en applikation som känns snabb och responsiv, vilket i sin tur kräver en noggrant utformad struktur för komponenter och rutter. Dataladdning är en annan viktig aspekt, särskilt när det gäller större applikationer, eftersom det kan påverka både prestanda och användarens upplevelse.

Hur MongoDB och FastAPI förenklar utveckling av moderna webbapplikationer

MongoDB erbjuder en rad funktioner som gör det till ett utmärkt val för utveckling av moderna webbapplikationer, särskilt när flexibilitet och skalbarhet är centrala behov. En av de mest framträdande egenskaperna hos MongoDB är dess förmåga att hantera komplexa, nästlade strukturer. MongoDB-dokument kan innehålla andra dokument eller arrayer av dokument, vilket är särskilt användbart för att representera de relationer som ofta finns i moderna webbtjänster. Till exempel kan alla kommentarer på ett blogginlägg lagras direkt i det specifika inlägget, vilket förenklar både lagring och hämtning av data. Denormalisering är en viktig del av denna struktur, vilket innebär att redundans uppmuntras för att förbättra läshastigheten och förenkla vissa typer av databehandling.

En annan fördel med MongoDB är den enkla och intuitiva syntaksen för de grundläggande CRUD-operationerna (Create, Read, Update, Delete). Kombinationen av dessa operationer med kraftfulla aggregationsramverk och projektioner gör att utvecklare kan hämta och manipulera data snabbt och effektivt. För dem med erfarenhet av SQL bör de flesta kommandon vara ganska bekanta, vilket gör övergången till MongoDB relativt enkel.

Trots dessa fördelar finns det vissa utmaningar att beakta. En av de främsta är att MongoDB saknar ett strikt schema, vilket kan kännas skrämmande för de som är vana vid striktare databasmodeller som de som finns i SQL. Denna flexibilitet innebär att större ansvar vilar på utvecklaren att säkerställa dataintegritet, särskilt på serverns baksida. Här kommer verktyg som Pydantic till nytta, ett bibliotek för Python som gör det enkelt att implementera strikt datavalidering och typkontroll.

För vissa typer av applikationer kan MongoDB:s avsaknad av komplexa join-operationer vara en nackdel. Detta kan göra det svårare att hantera relationer mellan flera datamängder, som är vanligt i traditionella SQL-databaser. För dessa användningsfall kanske en mer relationell databas är bättre lämpad.

När det gäller att skapa webbapplikationer är det viktigt att förstå vilken roll en API spelar i att koppla samman olika mjukvarusystem. FastAPI, som är ett ramverk för att bygga RESTful APIs, är ett utmärkt val för att bygga de API:er som interagerar med en MongoDB-databas. FastAPI utnyttjar moderna funktioner i Python, såsom typkomplettering och async/await-syntax, för att skapa ett mycket effektivt och skalbart API. En REST API är ett gränssnitt som tillåter olika program att kommunicera med varandra via HTTP-protokollet genom en cykel av förfrågningar och svar. Detta möjliggör att applikationer kan utbyta data på ett effektivt och säkert sätt.

FastAPI:s stora fördel är dess prestanda. Jämfört med andra Python-ramverk är FastAPI extremt snabbt, tack vare att det bygger på Starlette, vilket ger prestanda som vanligtvis är förknippad med mer effektiva teknologier som Node.js och Go. Ett annat stort plus är dess datavalidering och enkelhet, där Pydantic gör det möjligt att definiera komplexa dataobjekt och validera dessa på ett tydligt och kraftfullt sätt. Eftersom FastAPI bygger på Python-typer och Pydantic-modeller, blir utvecklingen mer intuitiv, vilket resulterar i snabbare utveckling och färre buggar.

FastAPI är också känd för sin enkla och detaljerade dokumentation. Eftersom det är baserat på OpenAPI-standarder kan dokumentationen genereras automatiskt via Swagger, vilket gör det lätt att komma igång och dokumentera API:et direkt. Detta är en stor fördel för utvecklare, då det sparar tid och gör att utvecklingscykeln blir betydligt smidigare.

En annan betydande fördel med FastAPI är dess asynkrona stöd. Genom att använda en ASGI-kompatibel server, som Uvicorn eller Hypercorn, kan FastAPI hantera asynkrona arbetsflöden utan att behöva importera asyncio-modulen i Python. Detta möjliggör effektiv hantering av samtidiga förfrågningar, vilket är avgörande för skalbarheten i moderna webbapplikationer.

Slutligen erbjuder FastAPI ett system för beroendeinjektion, vilket gör det möjligt att skapa återanvändbara och modulära komponenter för olika delar av API:t. Detta är en stor fördel för utvecklare som vill bygga komplexa funktioner som kan användas på flera olika ställen i deras applikation. Tillsammans med en logisk strukturering av applikationer gör det FastAPI till ett idealiskt val för hybridwebbapplikationer.

FastAPI:s popularitet växer snabbt, och för många utvecklare har det blivit det föredragna valet för att bygga RESTful APIs, särskilt när man använder en databas som MongoDB som har en flexibel och skalbar struktur. Kombinationen av MongoDB och FastAPI ger ett kraftfullt ramverk för att bygga robusta, högpresterande och skalbara webbapplikationer.

För att få ut det mesta av dessa teknologier är det viktigt att förstå vikten av att ha ett välstrukturerat backend-system. Både MongoDB och FastAPI erbjuder stor flexibilitet, men denna flexibilitet kräver också att utvecklare är medvetna om de potentiella utmaningarna, som dataintegritet och hantering av asynkrona förfrågningar. Det är också avgörande att förstå hur API:er fungerar på en djupare nivå, inte bara som ett gränssnitt utan som en central del av alla moderna applikationer.