Python - zajęcia 13
1) Ćwiczenie - Zgadnij liczbę interface

Sam interface:
import random
import streamlit as st
st.set_page_config(page_title="Zgadnij liczbę")
st.title("Zgadnij liczbę")
st.write("Witaj w grze Zgadnij Liczbe!")
st.write("Twoim zadaniem jest zgadniecie liczby z przedzialu 1-100")
moj_przycisk = st.button(label="Nowa gra")
st.write("Do zgadnięcia:")
st.write("Witaj w grze Zgadnij Liczbe!")
wybrana_liczba = st.slider(label="Jaka to liczba?",min_value=0, max_value=100, 25)
st.write(wybrana_liczba)
przycisk_prześlij = st.button(label="Prześlij")
st.write("Pozostałe próby:")
2) Zgadnij liczbę - ciąg dalszy z logiką
Co potrzebujemy do napisania tego:

import streamlit as st
import random
class ZgadnijLiczbe:
def __init__(self) -> None:
self.liczba_do_zgadniecia : int = random.randint(1, 100)
self.pozostale_proby : int = 7
self.wytypowana_liczba: int = -1
self.wygrana : bool = False
self.czy_uruchomiona = True
def zgaduj(self, wytypowana: int):
self.wytypowana_liczba = wytypowana
self.pozostale_proby -= 1
def sprawdz_wygrana(self):
if self.liczba_do_zgadniecia == self.wytypowana_liczba:
self.wygrana = True
self.czy_uruchomiona = False
def wyswietl_podpowiedz(self):
if self.pozostale_proby < 7:
if self.wytypowana_liczba < self.liczba_do_zgadniecia:
st.warning("Spróbuj wyższej.")
elif self.wytypowana_liczba > self.liczba_do_zgadniecia:
st.warning("Spróbuj niższej.")
def gratuluj(self):
if self.wygrana:
st.success("Brawo! To ta liczba.")
st.balloons()
def tworz_nowa_gre():
st.session_state.gra=ZgadnijLiczbe()
if "gra" not in st.session_state:
tworz_nowa_gre()
st.write("# Zgadnij liczbę!")
st.write("Gra polega na zgadnięciu liczby z zakresu 1-100.")
nowa_gra_btn = st.button(label="Nowa gra")
if nowa_gra_btn:
tworz_nowa_gre()
st.session_state.gra.gratuluj()
if st.session_state.gra.czy_uruchomiona:
st.session_state.gra.wyswietl_podpowiedz()
st.write(f"Do zgadnięcia: {st.session_state.gra.liczba_do_zgadniecia}")
wybor_slider = st.slider(
label="Jaka to liczba",
min_value=1,
max_value=100,
)
wyslij_btn = st.button(label="Prześlij.")
if wyslij_btn:
st.session_state.gra.zgaduj(wybor_slider)
st.session_state.gra.sprawdz_wygrana()
st.rerun()
st.write(f"Pozostałe próby: {st.session_state.gra.pozostale_proby}")
if st.session_state.gra.pozostale_proby <= 0:
st.session_state.gra.czy_uruchomiona = False
st.rerun()
3) Zewnętrzne źródła danych
Co zrobić jeśli chcemy skorzystać z jakichś źródeł danych pochodzących z zewnątrz? Jest możliwe tylko jeśli są udostępnione.
API (Application Programming Interface)
Aby poradzić sobie z tymi kwestiami, tworzone są API – skodyfikowany, ustalony sposób komunikacji między dwiema lub więcej aplikacjami.
To rodzaj umowy – „jeśli zadasz pytanie w ten sposób, dostaniesz ode mnie odpowiedź w takim formacie”. Tę spisaną umowę możemy potraktować jako rodzaj instrukcji umożliwiającej nam uzyskanie potrzebnych nam danych z zewnętrznej aplikacji.
4) REST API
To zestaw wytycznych jak konstruować API w pewien określony sposób. Zawiera opis funkcji, jakie API powinna realizować (GET, PUT, DELETE...) i sposób realizacji (np. brak przechowywania stanu pomiędzy zapytaniami, zapytania o ten sam zasób powinny wyglądać tak samo).
REST nie jest standardem / protokołem – to zestaw "luźnych" wytycznych, np. nie ustala w jakim formacie będą dostarczane dane, może to być JSON, XML itd. (chociaż najczęściej spotyka się JSON-a).
Jeśli szukacie czegoś "sztywniejszego", należy sięgnąć po alternatywy, np. SOAP (tam np. mamy sprecyzowane, że dane mają być wymieniane poprzez XML). Jednak ta elastyczność REST-a jest jednym z fundamentów sukcesu tego podejścia.
Aplikacje spełniające wymogi REST nazywane są RESTful.
5) Adres w przeglądarce

URL - to cały adres wskazujący zasób w internecie (jest rodzajem URI, które są ogólniejszą kategorią, obejmującą zasoby "pozainternetowe")
URI (Uniform Resource Identifier) - ciąg znaków, który jednoznacznie identyfikuje zasób. URI może wskazywać zasoby w internecie (np. URL) lub inne zasoby, np. lokalne pliki. Dzieli się na URL (lokalizację zasobu) i URN (nazwę zasobu).
6) Jak odpytujemy RESTowe API?
To proste - wysyłamy komunikat np. typu GET na odpowiedni adres, możemy to zrobić nawet bezpośrednio w przeglądarce:
https://api.frankfurter.app/latest
Co oznacza, że w opisie danego API musimy znaleźć te adresy, na które wysyłamy zapytania. Powyższa "końcówka" adresowa zwraca nam aktualne kursy popularnych walut dostarczone przez frankfurter.app.
7) Co jeśli chcemy uzyskać jakieś bardziej sprecyzowane wyniki?
Serwisy dają nam zazwyczaj jedną z dwóch możliwości:
- Inny adres dający nam te sprecyzowane dane.
- Parametry, które dodajemy do adresu lub w treści zapytania:
Przykład: https://api.frankfurter.app/latest?amount=10&from=PLN&to=EUR

Przypomnijcie sobie te wszystkie "dziwne" adresy jakie pojawiają się w Waszych przeglądarkach ;). Powyższe zapytanie zwróci nam następujący komunikat:

{
"amount": 10.0,
"base": "PLN",
"date": "2024-09-13",
"rates": {
"EUR": 2.3311
}
}
To są Json.
8) Jak może wyglądać dokumentacja do API?
Nie ma ustalonego standardu – dany zespół sam ustala, w jaki sposób będzie to dokumentować.
Dość popularnym rozwiązaniem jest Swagger – dokumentacja wykonana z jego pomocą może wyglądać np. tak:
https://wizard-world-api.herokuapp.com/swagger/index.html
Czasami Swagger jest dodawany, aby dać szansę na przetestowanie API opisanego już wcześniej, np.
https://api.psa.pulseway.com

9) Dodawanie / usuwanie danych z REST API?
Do pobierania (odczytywania) danych używaliśmy komunikatów typu GET.
To nie jedyna opcja - niektóre API dają nam szansę na publikowanie / modyfikowanie / usuwanie danych za pomocą komunikatów POST / PUT / DELETE.
Są też sytuacje, gdy twórcy API wymagają od nas przesłania jakichś danych i użycia komunikatu POST celem uzyskania informacji zwrotnej.
10) Jak testować API?
Oczywiście możemy wykorzystać do tego przeglądarkę. Szybko okaże się to niewygodne.
Wrzucanie nieprzetestowanych zapytań bezpośrednio do kodu też nie zawsze będzie dobrym pomysłem (... chociaż przyznaję, że w Pythonie zapisuje się to na tyle szybko, że czasami tak robię).
Na szczęście jest cała rzesza aplikacji do tego celu - takich jak Postman, Insomnia, Hoppscotch.



11) Zadanie w grupach
Popróbujcie darmowych API:
https://github.com/public-apis/public-apis
- zanotujcie co ciekawsze zapytania, przydadzą się później ;)
Uwierzytelnianie
Niektóre API mogą wymagać dodatkowego uwierzytelnienia. Metod jest kilka – np. JWT (JSON Web Tokens). Sugeruję wybrać API bez uwierzytelnienia ;)
12) Biblioteka requests
- służy do komunikacji z wykorzystaniem protokołu HTTP/HTTPS (czyli tego wykorzystywanego na stronach www)
https://requests.readthedocs.io/en/latest/
Jak zwykle zaczynamy od zaimportowania, po czym od razu możemy przystąpić do wysyłania zapytań – np. typu GET (czyli pobierz).
import requests
odpowiedz = requests.get("https://api.frankfurter.app/latest")
Zwróci nam to obiekt typu Response
. Jak go zdekodować?
Jeśli dostaliśmy JSON-a to np. tak:
odczytana = odpowiedz.json()