API:n versiointi on olennainen osa web-palvelujen kehittämistä ja ylläpitoa. Sen avulla voidaan tehdä muutoksia ja parannuksia järjestelmään ilman, että vanhat asiakkaat kokevat häiriöitä palvelun toiminnassa. Versiointi mahdollistaa myös yhteensopivuuden säilyttämisen eri käyttäjien kanssa ja antaa kehittäjille vapauden tehdä tarvittavia muutoksia palvelun toimintaan. Tämän artikkelin tarkoituksena on tutustuttaa lukija siihen, miten API:n versiointi toteutetaan käytännössä, erityisesti URL-pohjaisella lähestymistavalla, ja mitä kannattaa ottaa huomioon versioitaessa rajapintoja.

API:n versiointi voidaan toteuttaa useilla eri tavoilla, mutta yksi yleisimmistä ja yksinkertaisimmista menetelmistä on URL-polun versiointi. Tässä menetelmässä versio lisätään suoraan API:n URL-osoitteeseen, mikä mahdollistaa erilaisten versioiden rinnakkaisen olemassaolon ja käytön ilman, että ne häiritsevät toisiaan. Tällöin asiakas voi valita, minkä version rajapinnan haluaa käyttää, ja API pystyy palvelemaan sekä vanhempia että uudempia versioita samanaikaisesti.

Käytännön esimerkki: Versioinnin toteuttaminen

Oletetaan, että haluamme parantaa tehtävälistan tietoja lisäämällä uuden kentän, joka kertoo tehtävän prioriteetin. Prioriteetti on oletuksena "lower", mutta sen voi muuttaa tarpeen mukaan. Voimme toteuttaa tämän lisäämällä uuden version API:sta seuraavien vaiheiden mukaisesti.

Aluksi luomme uuden TaskV2-luokan, jossa on kaikki tarvittavat kentät, kuten title, description, status ja uusi priority-kenttä:

python
class TaskV2(BaseModel): title: str description: str status: str priority: str | None = "lower"

Seuraavaksi määrittelemme toiminnon, joka lukee kaikki tehtävät ja lisää niihin uuden kentän, priority:

python
def read_all_tasks_v2() -> list[TaskV2WithID]:
with open(DATABASE_FILENAME) as csvfile: reader = csv.DictReader(csvfile) return [TaskV2WithID(**row) for row in reader]

Näin olemme luoneet toisen version rajapinnasta. Seuraavaksi määrittelemme sen FastAPI:ssa, jossa määritämme polun /v2/tasks:

python
@app.get("/v2/tasks", response_model=list[TaskV2WithID]) def get_tasks_v2(): tasks = read_all_tasks_v2() return tasks

Nyt, kun käynnistämme palvelimen ja siirrymme interaktiivisiin dokumentaatioihin (http://localhost:8000/docs), näemme, että uusi GET /v2/tasks-polku on saatavilla ja se palauttaa tehtävät, joissa on myös uusi priority-kenttä. Samalla vanha GET /tasks-polku toimii edelleen.

Versiointistrategiat ja niiden vaikutukset

API:n versioinnissa on useita erilaisia lähestymistapoja. Yksi yleisimmistä on URL-polun versiointi, kuten edellä kuvattiin. Tämän lisäksi on olemassa muita versiointistrategioita, kuten kyselyparametreihin perustuva versiointi ja otsikkopohjainen versiointi. Näiden avulla API:n versio voidaan määritellä joko URL:n query-parametreissa tai HTTP-pyynnön otsikossa.

  • Query-parametriversiointi: Tässä lähestymistavassa versio määritellään API-pyynnön query-parametrissä, kuten https://api.example.com/resource?version=1. Tämä säilyttää URL:n perusrakenteen muuttumattomana, mutta lisää versiotiedon pyyntöön.

  • Otsikkopohjainen versiointi: Versio määritellään HTTP-pyynnön otsikossa, kuten X-API-Version: 1. Tämä lähestymistapa pitää URL:n puhtaana ja siistinä, mutta asiakas joutuu määrittämään version erikseen jokaisessa pyynnössä.

Kehittäjien ja API:n käyttäjien kannalta on tärkeää ymmärtää, että versioinnin tarkoituksena on antaa mahdollisuus kehittää API:a ja tuoda uusia toimintoja ilman, että vanhat versiot menevät rikki. Tämä on erityisen tärkeää pitkän aikavälin sovelluskehityksessä, jossa API:ta saatetaan käyttää monen eri organisaation tai käyttäjän toimesta.

Tärkeää muistettavaa

API:n versioinnin avulla voidaan tehdä merkittäviä parannuksia sovelluksen kehityksessä ja hallinnassa. Se ei kuitenkaan ole ainoa tekijä, joka vaikuttaa rajapinnan toimivuuteen. API:n käyttöä ja turvallisuutta tulisi myös harkita huolellisesti. Esimerkiksi OAuth2 voi olla olennainen osa API:n suojaamista ja varmistamista, että vain oikeutetuilla käyttäjillä on pääsy tietyille resursseille.

Lisäksi on huomattava, että version numerointi voi seurata semanttista versiointia, jossa MAJOR-versiot muuttuvat, kun tehdään ei-yhteensopivia muutoksia, ja MINOR- ja PATCH-versiot osoittavat taaksepäin yhteensopivia muutoksia. Tämä antaa sekä kehittäjille että käyttäjille selkeän kuvan siitä, millaisia muutoksia API:ssa on tapahtunut ja kuinka ne vaikuttavat olemassa oleviin toimiin.

Yhteenvetona voidaan todeta, että API:n versiointi ei ole vain tekninen vaatimus, vaan se on myös olennainen osa ohjelmistokehityksen elinkaaren hallintaa. Sen avulla voidaan varmistaa, että sovelluksen eri osat kehittyvät tasaisesti ilman, että vanhat toiminnot rikkoutuvat tai estävät uusien ominaisuuksien käyttöönottoa. Versioinnin oikea toteuttaminen on avainasemassa API:n pitkäikäisyyden ja vakauden varmistamisessa.

Kuinka optimoida SQL-kyselyitä ja suojata arkaluonteisia tietoja tehokkaasti?

SQL-kyselyiden suorituskyvyn optimointi on keskeinen osa modernien tietokantasovellusten kehitystä, erityisesti silloin, kun käytetään ORM-työkaluja kuten SQLAlchemy. Yksi yleisimmistä suorituskykyongelmista on niin sanottu N+1-kyselyongelma, jossa sovellus ensin hakee listan pääelementtejä ja tämän jälkeen silmukassa erikseen jokaisen liittyvän tiedon. Tämä johtaa tarpeettomaan määrään kyselyjä ja hidastaa sovellusta merkittävästi. Ongelman ratkaisemiseksi käytetään ns. eager loading -tekniikkaa, jossa haetaan pääelementtien lisäksi kaikki niihin liittyvät tiedot yhdellä kyselyllä esimerkiksi SQLAlchemyssa joinedload-optioita hyödyntäen. Tämä mahdollistaa yhdistetyn JOIN-kyselyn, mikä eliminoi ylimääräiset N kyselyä.

JOIN-lauseen käyttöä kannattaa kuitenkin harkita tarkkaan. Vaikka yhdistämällä tauluja kyselyistä tulee usein luettavampia ja tehokkaampia, ylimääräiset JOINit voivat tuoda tarpeettomia tietoja ja kuormittaa suoritusta. Esimerkiksi, jos haetaan tietyn tapahtuman sponsoreiden nimet ja lahjoitussummat, kannattaa liittyä vain tarpeellisiin tauluihin ja suodattaa tiedot WHERE-lauseella ilman turhia JOINeja, jolloin tietokanta ei tee turhaa työtä eikä siirry ylimääräisiä tietoja.

Tietokannasta kannattaa aina hakea mahdollisimman vähän tietoa. SQLAlchemyssa load_only-funktiolla voi määritellä, että haetaan vain tarvittavat sarakkeet, mikä vähentää muistin käyttöä ja nopeuttaa kyselyiden suorittamista. Tämä on erityisen tärkeää suurissa sovelluksissa ja analytiikassa, jossa haetaan usein hyvin suuria tietomassoja. Esimerkiksi lipputietoja haettaessa riittää usein vain lipun tunniste, käyttäjä ja hinta ilman kaikkia muita kenttiä.

SQL-kyselyiden optimointi ei kuitenkaan rajoitu pelkästään ORM:n asetuksiin tai yksittäisten kyselyiden hienosäätöön. Eri SQL-tietokannat tarjoavat erilaisia mahdollisuuksia ja rajoituksia, jotka vaikuttavat suorituskykyyn. Joissakin tietokannoissa on tuki partitioinnille, shardingille, replikaatiolle tai hajautetulle käsittelylle, jotka mahdollistavat skaalaamisen ja parantavat saatavuutta. Myös kyselyjen optimointitekniikat, kuten kustannuspohjainen optimointi, kyselyjen uudelleenkirjoitus tai välimuisti, voivat merkittävästi nopeuttaa suorituskykyä. Tietokantojen eri tallennusmoottorit, transaktiomallit ja indeksointimenetelmät vaikuttavat lisäksi siihen, miten hyvin ne soveltuvat erilaisiin käyttötapauksiin.

Tietokantavalintaa tehtäessä on siksi suositeltavaa tehdä realistisia suorituskykytestejä ja vertailla eri ratkaisujen toimintaa käytännön kuormituksella. Mittareina kannattaa käyttää muun muassa läpimenoaikaa, viivettä, tietojen tarkkuutta ja järjestelmän luotettavuutta. Näin voidaan löytää juuri omaan sovellukseen sopivin tietokanta ja samalla tunnistaa mahdolliset pullonkaulat sekä parannuskohteet kyselyissä ja tietokantarakenteissa.

Tietoturva on toinen ratkaiseva näkökulma SQL-tietokantojen käytössä, erityisesti kun käsitellään arkaluontoisia tietoja kuten henkilö- tai maksutietoja. Tiedon salaaminen on välttämätöntä, jotta tieto ei ole luettavissa ilman oikeita avaimia, vaikka tietokanta joutuisikin hyökkäyksen kohteeksi. Symmetrinen salaus, kuten Fernet-kirjaston tarjoama AES-pohjainen salaus, mahdollistaa tiedon salaamisen ja purkamisen samalla avaimella, mikä on hyödyllistä tietojen lukemisen kannalta sovelluksessa.

Salaus toteutetaan usein lisäämällä tietokantaan oma taulunsa esimerkiksi luottokorttitiedoille, joissa herkät kentät kuten kortin numero ja CVV tallennetaan salattuina. Tällöin on tärkeää huolehtia myös avainten turvallisesta hallinnasta, jotta avain ei päädy vääriin käsiin. Salaustekniikoiden käyttö sovelluksessa vaatii huolellista suunnittelua, jotta tietojen hakeminen ja käsittely onnistuu saumattomasti mutta turvallisesti. Tietokannan tasolla tämä tarkoittaa usein sitä, että sovellus suorittaa salauksen ja purun ennen tietojen tallennusta ja noutamista, jolloin varsinaiseen tietokantaan tallentuu vain salattu data.

Tietokannan suorituskyvyn ja tietoturvan yhteensovittaminen vaatii siis laaja-alaista ymmärrystä tietokantojen toiminnasta, kyselyiden rakentamisesta ja salausmenetelmistä. Käytännön toteutuksessa on otettava huomioon sekä optimoitujen SQL-kyselyiden rakentaminen että salausavainten hallinta ja turvallinen koodauskäytäntö. Näin varmistetaan, että sovellus pystyy palvelemaan käyttäjiä nopeasti ja luotettavasti, mutta samalla suojaa heidän arkaluonteiset tietonsa mahdollisimman tehokkaasti.

Miten luoda ja integroida FastAPI-sovellus, joka yhdistää koneoppimismalleja ja kehittyneitä kielimalleja?

FastAPI on yksi suosituimmista Python-web-sovelluskehyksistä, joka on tunnettu nopeudestaan ja joustavuudestaan. Se mahdollistaa tehokkaan työskentelyn API:en kanssa ja on erityisen hyödyllinen koneoppimismallien integroimisessa. Tässä käsittelemme, kuinka FastAPI:tä voi käyttää yhdessä koneoppimismallien, kuten ML-mallien ja luonnollisen kielen käsittelyn (NLP) mallien, kanssa. Esimerkiksi luomme yksinkertaisen lääketieteellisen diagnostiikkatyökalun ja älykkään reseptisuositusbotin.

FastAPI-sovelluksen luominen, joka yhdistää koneoppimismalleja, on prosessi, jossa yhdistetään useita osia. Ensimmäinen vaihe on API-päätteiden (endpoints) luominen ja niiden määrittäminen siten, että ne pystyvät vastaanottamaan tietoja ja palauttamaan ennusteita. Tällöin käytämme Pydanticia, joka mahdollistaa tietomallien luomisen dynaamisesti. Esimerkiksi luomme Symptoms-luokan, joka ottaa oireet parametrina ja rajoittaa mallin ensimmäisiin kymmeneen oireeseen:

python
from pydantic import create_model
from app.utils import symptoms_list query_parameters = {symp: (bool, False) for symp in symptoms_list[:10]} Symptoms = create_model("Symptoms", **query_parameters)

Tämä luo mallin, joka hyväksyy kymmentä ensimmäistä oiretta parametreina. Seuraavaksi määrittelemme GET-päätteen /diagnosis, joka käyttää aiemmin luotua mallia oireiden vastaanottamiseen ja niiden perusteella ennusteen palauttamiseen. Ennuste tehdään koneoppimismallilla, joka on integroitu FastAPI-sovellukseen.

python
@app.get("/diagnosis")
async def get_diagnosis(symptoms: Annotated[Symptoms, Depends()]):
array = [
int(value) for _, value in symptoms.model_dump().items()] array.extend([0] * (len(symptoms_list) - len(array))) diseases = ml_model["doctor"].predict([array]) return {"diseases": [disease for disease in diseases]}

Tämän jälkeen käyttäjä voi testata sovellusta helposti selaimessa, sillä FastAPI tarjoaa automaattisen dokumentaation ja käyttöliittymän. Käyttäjä voi valita oireet ja saada diagnoosin "AI-lääkäriltä", joka on juuri luotu sovellukseen. Tämä malli voi olla laajennettavissa siten, että samassa sovelluksessa voidaan käyttää useita koneoppimismalleja eri päätteissä, mikä tekee sovelluksesta monikäyttöisemmän.

FastAPI-sovelluksen tehokkuus ja monipuolisuus korostuvat erityisesti silloin, kun se yhdistetään modernien kielimallien, kuten Cohere:n tai GPT-mallien kanssa. Cohere:n mallit voivat käsitellä luonnollista kieltä ja luoda älykkäitä keskusteluja, mikä avaa mahdollisuuksia rakentaa esimerkiksi chatbotteja. Esimerkiksi reseptisuositusbotin luominen voi tapahtua näin:

python
from cohere import AsyncClient
client = AsyncClient() SYSTEM_MESSAGE = ( "You are a skilled Italian top chef " "expert in Italian cuisine tradition " "that suggests the best recipes unveiling " "tricks and tips from Grandma's Kitchen " "shortly and concisely." ) async def generate_chat_completion(user_query=" ", messages=[]): try: response = await client.chat( message=user_query, model="command-r-plus", preamble=SYSTEM_MESSAGE, chat_history=messages ) messages.extend([ ChatMessage(role="USER", message=user_query), ChatMessage(role="CHATBOT", message=response.text) ]) return response.text except ApiError as e: raise HTTPException(status_code=e.status_code, detail=e.body)

Tässä tapauksessa käytämme Cohere:n Command R+ -mallia, joka on suunniteltu erityisesti keskustelukontekstien käsittelemiseen ja pitkien vuorovaikutusten ymmärtämiseen. Botin tehtävänä on antaa käyttäjälle reseptisuosituksia ja keittiövinkkejä Italian keittiöstä.

Kun nämä mallit on integroitu FastAPI-sovellukseen, käyttäjä voi helposti vuorovaikuttaa sovelluksen kanssa ja saada vastauksia tai suosituksia. Tämä yhdistelmä – FastAPI ja koneoppimismallit – luo tehokkaan ja joustavan alustan erilaisten AI-pohjaisten sovellusten rakentamiseen.

On tärkeää muistaa, että API-avaimet, kuten Cohere:n API-avain, tulee aina pitää turvassa. Ne eivät saa olla versionhallinnassa, kuten GitHubissa, sillä ne voivat päätyä vääriin käsiin ja johtaa turvallisuusongelmiin. Tämän vuoksi on suositeltavaa käyttää ympäristömuuttujia (kuten .env-tiedostoja) API-avainten hallintaan.

Jatkamalla tämän prosessin parissa, voi rakentaa laajempia ja monimutkaisempia sovelluksia, jotka yhdistävät useita koneoppimismalleja ja hyödyntävät moderneja kielimallien tarjoamia mahdollisuuksia. FastAPI tarjoaa kaikki tarvittavat työkalut ja joustavuuden, jotta tällaiset sovellukset voidaan toteuttaa nopeasti ja tehokkaasti.

Miten luoda ja käyttää Python-paketteja Hatchin avulla FastAPI:ssa?

FastAPI-sovellusten kehittäminen edellyttää joskus mukautettujen pakettien luomista, jotka voidaan helposti integroida muihin projekteihin. Yksi tehokas työkalu tähän on Hatch, joka on Pythonin monipuolinen pakettienhallinta- ja ympäristöhallintajärjestelmä. Hatch tarjoaa joustavuutta ja tehokkuutta, ja sen avulla voidaan hallita sekä koodin pakkaamista että useiden virtuaaliympäristöjen luomista. Tässä käsitellään, miten luodaan oma paketti FastAPI-sovellukselle ja tuodaan se toiseen projektiin käyttäen Hatchia.

Aloitetaan FastAPI-reitittimen määrittämisestä. Voimme luoda yksinkertaisen reitittimen, joka palauttaa tervetuloviestin, kuten seuraavassa esimerkissä:

python
app = APIRouter()
@app.get("/") def read_root(): return { "message": "Welcome to the FastAPI Cookbook Application!" }

Tämä koodi luo perusreitin, joka palauttaa sanoman. Seuraavaksi on tärkeää tuoda tämä reititin osaksi projektia. Tämä tehdään importoimalla reititin fca_server.main-moduulista src/fca_server.__init__.py -tiedostoon seuraavasti:

python
from fca_server.main import router

Näin reititin voidaan tuoda käyttöön muissa projekteissa suoraan fca_server-paketista. Seuraava vaihe on paketin jakaminen ulkopuolisiin projekteihin.

Paketin luominen Hatchilla

Kun paketti on valmis, voimme käyttää Hatchia sen luomiseen. Tämä tehdään seuraavalla komennolla, joka luo paketin tar.gz-muodossa:

bash
$ hatch build -t sdist ../dist

Tämän komennon jälkeen Hatch luo tiedoston fca_server-0.0.1.tar.gz, joka tallennetaan dist-kansioon. Tämä paketti voidaan siirtää ja asentaa toiseen projektiin.

Paketin testaaminen toisessa projektissa

Paketin testaaminen toisessa projektissa on yksinkertaista. Ensimmäiseksi luomme uuden projektin, joka käyttää fca_server-pakettia. Luo uusi kansio esimerkiksi nimellä import-fca-server, ja käytä sitä projektin juurihakemistona. Tämän jälkeen luo paikallinen virtuaaliympäristö seuraavalla komennolla:

bash
$ python -m venv .venv

Aktivoi ympäristö. Linux- tai macOS-käyttöjärjestelmässä tämä tehdään seuraavalla komennolla:

bash
$ source .venv/Scripts/activate

Windows-käyttöjärjestelmässä aktivointi tapahtuu näin:

bash
$ .venv\Scripts\activate

Asenna seuraavaksi fca_server-paketti pip-komennolla:

bash
$ pip install ..\dist\fca_server-0.0.1.tar.gz

Nyt voit käyttää fca_server-pakettia ja tuoda reitittimen main.py-tiedostoon:

python
from fastapi import FastAPI
from fca_server import router app = FastAPI( title="Import FCA Server Application" ) app.include_router(router)

Käynnistä palvelin komennolla:

bash
$ fastapi run

Mene sitten selaimeen osoitteeseen http://localhost:8000/docs ja tarkista, että ulkopuolinen paketti on tuotu oikein. Näin olet luonut mukautetun paketin ja tuonut sen toiseen projektiin onnistuneesti.

Hatchin edut ja lisäominaisuudet

Hatch ei ole vain yksinkertainen pakettienhallintatyökalu. Se on monipuolinen ja tehokas järjestelmä, joka voi auttaa sinua hallitsemaan useita virtuaaliympäristöjä ja mukauttamaan projektisi rakennusprosesseja. Hatchilla voit esimerkiksi määrittää, mihin virtuaaliympäristötiedostot sijoitetaan. Tämä voidaan tehdä config.toml-tiedoston avulla, jossa on Hatchin konfiguraatioasetukset.

Hatch tukee myös pakettien luomista wheel-muodossa, joka on binäärinen jakeluformaatti, joka on tehokkaampi ja yhteensopivampi kuin perinteinen lähdekoodin jakelu. Lisäksi Hatchilla voidaan helposti julkaista paketteja Python Package Indexiin (PyPI), jolloin muut voivat löytää ja asentaa ne helposti.

Pyproject.toml ja ympäristönhallinta

Yksi tärkeimmistä elementeistä Python-projektin hallinnassa on pyproject.toml-tiedosto, joka määrittää rakennusjärjestelmän ja muut projektin metatiedot. Tämä tiedosto on keskeinen osa Hatchin toimintaa ja sen avulla voidaan määrittää riippuvuudet ja muut projektin asetukset. Hatch tukee pyproject.toml-tiedoston käyttöä, mikä auttaa projektin rakennusprosessin yksinkertaistamisessa ja standardoimisessa.

Hatchin avulla voidaan myös hallita projektin eri ympäristöjä, mikä mahdollistaa useiden erillisten ympäristöjen luomisen ja hallinnan samalla projektilla. Tämä on erityisen hyödyllistä suurissa projekteissa, joissa tarvitsee testata useita eri ympäristöjä tai versioita samanaikaisesti.

Lopuksi, Hatchin virallinen dokumentaatio tarjoaa kattavat ohjeet sen eri ominaisuuksien ja toimintojen hyödyntämiseen. Se auttaa ymmärtämään, miten projekteja voidaan hallita ja optimoida tehokkaasti Hatchin avulla.