Cele lekcji
Po tej lekcji:
- rozumiesz, czym jest webservice (API),
- wiesz, czym różni się strona internetowa od API,
- potrafisz uruchomić serwer Node.js w Replit,
- potrafisz odczytać dane z pliku JSON przez endpoint
/players, - wiesz, jak aplikacja (gra, strona) może pobierać dane z serwera.
Wprowadzenie
Na początku ustalamy jedno bardzo ważne rozróżnienie:
Strona internetowa pokazuje coś człowiekowi.
API (webservice) zwraca dane, które czyta program.
Dzisiaj budujemy API, a nie klasyczną stronę.
Zrobimy to za pomocą on-linowego środowiska replit

zakładamy konto

Krok 1. Utworzenie projektu Node.js w Replit
Przechodzimy w tryb Developer Frameworks

Wybieramy Node.js

Rys. Tworzymy nową aplikację w Replit, wybierając Node.js jako technologię.
Po utworzeniu projektu widzisz:
- plik
index.js, - plik
package.json, - konsolę uruchomieniową.

Rys. ekran z wyborem Node.js / startowy widok projektu w Replit
Remiksujemy projekt
Krok 2. Pierwszy działający serwer
W pliku index.js uruchamiamy najprostszy serwer:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Webservice działa");
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log("Serwer działa na porcie", port);
});
W tools&files należy dodać Preview

Uruchamiamy projekt przyciskiem Run.
Jeśli wszystko działa poprawnie:
- w konsoli pojawia się komunikat o porcie,
- w podglądzie (Preview) widać tekst „Webservice działa 🚀”.

Rys. konsola + Preview z napisem „Webservice działa”
Krok 3. Dodanie pliku z danymi – db.json

Tworzymy nowy plik o nazwie db.json.

To jest nasza prosta baza danych w formacie JSON:
{
"players": [
{ "id": 1, "name": "Tymek", "score": 1200 },
{ "id": 2, "name": "Adam", "score": 950 }
]
}

Rys. Lista plików z widocznym db.json + zawartość pliku
Wyjaśniamy:
- JSON to format danych, nie strona,
- takie dane czyta aplikacja, a nie człowiek.
Krok 4. Odczyt danych z JSON przez API
Rozszerzamy index.js, aby serwer:
- czytał dane z
db.json, - zwracał je pod adresem
/players.
const express = require("express");
const fs = require("fs");
const app = express();
app.use(express.json());
function readDB() {
return JSON.parse(fs.readFileSync("db.json", "utf8"));
}
app.get("/players", (req, res) => {
const db = readDB();
res.json(db.players);
});
app.get("/", (req, res) => {
res.send("Webservice działa Wejdź na /players");
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log("Serwer działa na porcie", port);
});
Po uruchomieniu:
/pokazuje komunikat tekstowy,/playerszwraca czysty JSON.
Otwieramy przeglądarkę w new tab

Pojawi się ten sam monit co wyżej, ale w przeglądarce

dopisujemy /players

Rys. Adres /players w przeglądarce z widocznym JSON-em
Krok 5. Dlaczego to NIE jest strona?
W przeglądarce widzisz dane w formie:
[
{ "id": 1, "name": "Tymek", "score": 1200 },
{ "id": 2, "name": "Adam", "score": 950 }
]
To wygląda „jak tekst”, bo:
- to nie jest dla człowieka,
- to jest dla programu (gry, strony, aplikacji).
Tak właśnie działają:
- gry online,
- rankingi,
- panele admina,
- aplikacje mobilne.
Podsumowanie lekcji
Dzisiaj:
- uruchomiłeś prawdziwy serwer,
- stworzyłeś API,
- połączyłeś kod z plikiem JSON,
- zobaczyłeś, skąd aplikacje biorą dane.
To dokładnie ten sam mechanizm, który stoi za dużymi serwisami — tylko w uproszczonej, edukacyjnej wersji.
Co dalej (zapowiedź kolejnej lekcji)
Na następnych zajęciach możemy:
- dodać prostą stronę HTML, która pobiera dane z
/players, - połączyć API z grą lub Twoim projektem,
- rozbudować API (dodawanie / usuwanie graczy),
- porozmawiać o bezpieczeństwie danych.
Czyli wykonujemy te wszystkie czynności w środowisku on-linowym, który moglibyśmy uruchomić lokalnie.
Opis plików
index.js
// Importujemy bibliotekę express.
// Express to framework, który pozwala bardzo łatwo tworzyć serwer HTTP.
const express = require("express");
// Importujemy moduł fs (file system).
// Pozwala on czytać i zapisywać pliki na dysku (u nas: db.json).
const fs = require("fs");
// Tworzymy obiekt aplikacji serwera.
// Od tej chwili 'app' reprezentuje nasz serwer.
const app = express();
// Mówimy serwerowi, że będzie odbierał dane w formacie JSON.
// Dzięki temu możemy czytać req.body w zapytaniach POST.
app.use(express.json());
// ======================================================
// FUNKCJE POMOCNICZE – OBSŁUGA PLIKU db.json
// ======================================================
// Funkcja do odczytu danych z pliku db.json.
// Czytamy plik jako tekst, a potem zamieniamy go na obiekt JavaScript.
function readDB() {
return JSON.parse(
fs.readFileSync("db.json", "utf8")
);
}
// Funkcja do zapisu danych do pliku db.json.
// Zamieniamy obiekt JavaScript na JSON i zapisujemy do pliku.
// 'null, 2' sprawia, że plik jest czytelnie sformatowany.
function writeDB(db) {
fs.writeFileSync(
"db.json",
JSON.stringify(db, null, 2)
);
}
// ======================================================
// ENDPOINTY API
// ======================================================
// ------------------------------------------------------
// GET /players
// Ten endpoint zwraca listę wszystkich graczy.
// Używany np. przez stronę, grę lub aplikację.
app.get("/players", (req, res) => {
// Odczytujemy dane z pliku db.json
const db = readDB();
// Zwracamy tylko tablicę graczy w formacie JSON
res.json(db.players);
});
// ------------------------------------------------------
// POST /players
// Ten endpoint dodaje nowego gracza do "bazy danych".
app.post("/players", (req, res) => {
// Pobieramy dane wysłane w zapytaniu (z body).
// Oczekujemy, że będzie tam name i score.
const { name, score } = req.body;
// Sprawdzamy, czy przesłano imię gracza.
// Jeśli nie – zwracamy błąd 400 (złe dane).
if (!name) {
return res
.status(400)
.json({ error: "Brak name" });
}
// Odczytujemy aktualne dane z pliku db.json
const db = readDB();
// Wyznaczamy ID nowego gracza.
// Jeśli gracze już istnieją – bierzemy największe ID i dodajemy 1.
// Jeśli nie ma żadnych graczy – zaczynamy od ID = 1.
const nextId = db.players.length
? Math.max(…db.players.map(p => p.id)) + 1
: 1;
// Tworzymy obiekt nowego gracza.
const player = {
id: nextId,
name: name,
score: Number(score) || 0 // jeśli score nie podano – ustawiamy 0
};
// Dodajemy nowego gracza do tablicy
db.players.push(player);
// Zapisujemy zmienione dane z powrotem do db.json
writeDB(db);
// Zwracamy dodanego gracza oraz kod 201 (utworzono)
res.status(201).json(player);
});
// ======================================================
// START SERWERA
// ======================================================
// Ustalamy port serwera.
// Replit ustawia PORT automatycznie, lokalnie będzie to 3000.
const port = process.env.PORT || 3000;
// Endpoint główny "/".
// Nie jest to API, tylko informacja dla człowieka.
app.get("/", (req, res) => {
res.send("Webservice działa. Wejdź na /players");
});
// Uruchamiamy serwer i zaczynamy nasłuchiwać na porcie.
app.listen(port, () => {
console.log("Serwer działa na porcie", port);
});
JSON

Zasada działania
Jak działa ten webservice? (od środka)
Ta aplikacja nie jest stroną internetową w klasycznym sensie.
To jest serwer, czyli program, który czeka na zapytania i odpowiada na nie danymi.
Żeby to dobrze zrozumieć, rozbijmy całość na kilka kluczowych pojęć.
1. Co to jest serwer? (app)
Serwer to program działający cały czas w tle, który:
- nasłuchuje na określonym porcie (np. 3000),
- odbiera zapytania z Internetu,
- decyduje, jak na nie odpowiedzieć.
W naszym kodzie serwerem jest ten obiekt:
const app = express();
Od tej chwili:
appreprezentuje serwer,- wszystko, co piszemy później (
app.get,app.post), to instrukcje dla serwera, jak ma się zachować.
Można to porównać do:
recepcji w budynku, która przyjmuje ludzi i kieruje ich do odpowiednich drzwi.
Serwer nie zgaduje, co ma zrobić — ma dokładnie zapisane reguły.
2. Czym jest endpoint? (/players)
Endpoint to konkretny adres, pod którym serwer wykonuje konkretną akcję.
W naszym przypadku:
app.get("/players", ...)
oznacza:
- jeśli ktoś wejdzie na adres
/players, - serwer zwróci listę graczy.
Endpoint to:
- nie cały serwer,
- nie cała aplikacja,
- tylko jedno wejście do serwera.
Analogicznie:
- serwer = cały budynek,
- endpoint = konkretne drzwi z napisem „Gracze”.
Dlatego:
/pokazuje informację tekstową,/playerszwraca dane w JSON.
Każdy endpoint ma:
- adres (
/players), - metodę (
GET,POST), - konkretne zachowanie.
3. Różnica między GET a POST
To jest jeden z najważniejszych momentów tej lekcji.
GET – pobieranie danych
app.get("/players", ...)
GET oznacza:
- „chcę coś dostać”,
- nie zmieniam danych,
- tylko odczytuję.
Przykład:
- strona pobiera listę graczy,
- gra pobiera ranking,
- aplikacja mobilna pobiera dane użytkownika.
GET:
- jest bezpieczny,
- nie powinien nic zapisywać,
- można go wywołać zwykłą przeglądarką.
POST – wysyłanie danych
app.post("/players", ...)
POST oznacza:
- „chcę coś dodać lub zmienić”,
- wysyłam dane do serwera,
- serwer zapisuje je w „bazie”.
W naszym przypadku POST:
- dodaje nowego gracza,
- zapisuje go do
db.json.
POST:
- zmienia dane,
- nie jest do „klikania” w pasku adresu,
- zwykle używa go formularz, gra lub aplikacja.
To dlatego:
/playersw przeglądarce pokazuje listę,- ale dodawanie gracza wymaga POST.
4. Dlaczego JSON to NIE jest strona HTML?
Gdy wchodzisz na /players, widzisz coś takiego:
[
{ "id": 1, "name": "Tymek", "score": 1200 },
{ "id": 2, "name": "Adam", "score": 950 }
]
To nie jest strona internetowa, bo:
- nie ma HTML,
- nie ma stylu,
- nie jest „ładne”.
I bardzo dobrze.
JSON
- jest dla programów, nie dla ludzi,
- jest prosty i jednoznaczny,
- idealnie nadaje się do przesyłania danych.
Dlatego:
- strona HTML pobiera JSON,
- gra pobiera JSON,
- aplikacja mobilna pobiera JSON.
A potem:
- sama decyduje, jak to wyświetlić.
Serwer:
- nie dba o wygląd,
- dba o dane.
Podsumowanie – jak to wszystko działa razem
- Serwer (
app) działa cały czas. - Endpointy (
/players) to konkretne „wejścia”. - GET służy do pobierania danych.
- POST służy do ich dodawania.
- JSON to format danych dla programów, nie dla ludzi.
- Wygląd (HTML, CSS) to kolejny etap, nie obowiązek serwera.
Dlaczego to jest „Internet od środka”?
Bo dokładnie tak:
- działa ranking w grze,
- działa sklep internetowy,
- działa Instagram, YouTube, dziennik elektroniczny.
Różnica jest tylko w skali, nie w zasadzie działania.
JSON
Czym jest plik package.json?
Plik package.json to opis projektu, a nie kod programu.
Można o nim myśleć jak o:
- metryczce aplikacji,
- instrukcji obsługi dla komputera,
- liście składników, które są potrzebne, żeby program działał.
Node.js nie zgaduje, czego potrzebuje aplikacja — wszystko ma zapisane właśnie tutaj.
Cały plik package.json
{
"name": "nodejs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/node": "^22.13.11",
"express": "^5.2.1"
}
}
Teraz rozłóżmy to linijka po linijce.
1. Nazwa projektu
"name": "nodejs"
To jest:
- nazwa aplikacji,
- identyfikator projektu.
Nie wpływa bezpośrednio na działanie serwera, ale:
- pozwala rozpoznać projekt,
- jest ważna przy większych aplikacjach lub publikacji.
-> Można to porównać do nazwy gry lub programu.
2. Wersja aplikacji
"version": "1.0.0"
To numer wersji projektu.
Zapis 1.0.0 oznacza:
- 1 – główna wersja (duża zmiana),
- 0 – nowe funkcje,
- 0 – poprawki błędów.
To jest informacja głównie dla programistów, a nie dla użytkowników.
3. Opis projektu
"description": ""
Miejsce na krótki opis:
- co robi aplikacja,
- do czego służy.
U nas jest puste, bo:
- projekt jest edukacyjny,
- nie musimy tego opisywać.
4. Plik startowy aplikacji
"main": "index.js"
To jedna z najważniejszych linijek.
Oznacza:
„Gdy uruchamiasz ten projekt, zacznij od pliku
index.js.”
Czyli:
- Node.js wie, od czego zacząć,
- nie musi zgadywać, który plik jest główny.
Dlatego cały serwer znajduje się właśnie w index.js.
5. Skrypty (czyli polecenia)
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
To są gotowe polecenia, które można uruchomić jednym słowem.
Na przykład:
npm testnpm start(jeśli by istniał)
W tym projekcie:
- skrypt
testjest domyślny, - nie korzystamy z niego.
Ważne:
-> Replit uruchamia aplikację bezpośrednio, więc nie musimy tu nic zmieniać.
6. Słowa kluczowe, autor, licencja
"keywords": [],
"author": "",
"license": "ISC"
To są informacje:
- opisowe,
- formalne,
- ważne przy publikowaniu projektu.
To nie wpływa na działanie serwera.
Można to porównać do:
- autora książki,
- informacji na okładce.
7. Najważniejsza sekcja – dependencies
"dependencies": {
"@types/node": "^22.13.11",
"express": "^5.2.1"
}
To jest lista bibliotek, bez których aplikacja nie zadziała.
-> express
"express": "^5.2.1"
To:
- framework do tworzenia serwera,
- bez niego nie byłoby
app.get()aniapp.post().
Jeśli usuniemy Express:
- serwer przestaje działać.
-> @types/node
"@types/node": "^22.13.11"
To:
- informacje pomocnicze o Node.js,
- ułatwiają pracę edytorowi kodu.
Nie jest to „silnik” aplikacji, tylko:
- podpowiedzi dla programisty,
- pomoc w wykrywaniu błędów.
Co robi Replit z package.json?
Gdy tworzysz projekt:
- Replit czyta
package.json - Widzi
dependencies - Automatycznie:
- pobiera Express,
- instaluje potrzebne pakiety
- Uruchamia
index.js
Dlatego:
- nie musieliśmy nic instalować ręcznie,
- wszystko zadziałało „samo”.
Podsumowanie – po co jest package.json?
package.json:
- mówi co to za projekt,
- mówi od czego zacząć (
index.js), - mówi jakie biblioteki są potrzebne,
- pozwala innemu komputerowi uruchomić ten sam projekt.
