Eventingo — znajdź co gra w Twoim mieście
Prosta aplikacja webowa, która odpowiada na jedno pytanie: co się dzieje w podanym mieście przez najbliższe 7 dni? Użytkownik wpisuje nazwę miasta, serwer odpytuje Ticketmaster Discovery API i zwraca listę wydarzeń — koncertów, festiwali, spektakli — z datą, miejscem i linkiem do zakupu biletów.
Projekt skupiony na jednej kompetencji: integracji z zewnętrznym REST API. Żadnej bazy danych, żadnych sesji, żadnej autentykacji — tylko formularz, żądanie HTTP do Ticketmaster i wyrenderowany wynik. Cały backend to 77 linii JavaScript.
Zakres dat jest obliczany automatycznie po stronie serwera — zawsze “teraz” do “teraz + 7 dni”,
sformatowane do wymaganego przez API formatu ISO 8601 UTC (2024-11-15T00:00:00Z).
Użytkownik nie musi podawać dat.
01Wygląd aplikacji
Ciemna, eventowa estetyka — pełnoekranowe hero z gradientowym tłem na zdjęciu, białe logo z grubą ramką i dużymi literami, formularz wyszukiwania wyśrodkowany na środku ekranu. Po wyszukaniu strona przewija się do siatki kart wydarzeń na głębokiej bordo-pomarańczowej palecie.
↑ rekonstrukcja interfejsu na podstawie kodu CSS i HTML
02Jak działa aplikacja
Użytkownik wpisuje miasto
Formularz HTML wysyła POST do /submit z polem location.
Serwer oblicza zakres dat
Node.js buduje dwa obiekty Date — teraz i teraz+7 dni — i formatuje je do ISO 8601 UTC wymaganego przez Ticketmaster (YYYY-MM-DDTHH:mm:00Z).
Axios odpytuje Ticketmaster Discovery API v2
Parametry: apikey, city, startDateTime, endDateTime. Odpowiedź zawiera zagnieżdżoną strukturę _embedded.events.
Mapowanie danych
Serwer wyciąga tylko potrzebne pola: event.name, event.dates.start.localDate, event._embedded.venues[0].name, event.url.
EJS renderuje wynik
Przetworzona tablica trafia do szablonu index.ejs jako zmienna events. Pętla <% events.forEach() %> generuje karty. Jeśli wynik pusty — wyświetlany error.
03Backend — 77 linii
Cały serwer to jeden plik index.js. Dwa endpointy: GET / zwraca pustą stronę, POST /submit wykonuje całą logikę.
// Formatowanie dat do ISO 8601 UTC — wymaganie Ticketmaster API
const getFormattedDate = (date) => {
const pad = (n) => String(n).padStart(2, '0');
return `${date.getUTCFullYear()}-${pad(date.getUTCMonth()+1)}-${pad(date.getUTCDate())}`
+ `T${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:00Z`;
};
const startDate = new Date(); // teraz
const endDate = new Date();
endDate.setDate(startDate.getDate() + 7); // +7 dni
// Zapytanie do Ticketmaster Discovery API v2
const response = await axios.get(API_URL, {
params: {
apikey: API_KEY,
startDateTime: formattedStartDate,
endDateTime: formattedEndDate,
city: location, // z req.body.location
}
});
// Mapowanie odpowiedzi API → prosty obiekt
const eventsArray = response.data._embedded?.events || [];
const events = eventsArray.map((event) => ({
eventName: event.name,
eventDate: event.dates.start.localDate,
eventLocation: event._embedded.venues[0].name,
eventUrl: event.url
}));
Obsługa błędów: blok try/catch przechwytuje wszelkie problemy — brak połączenia z API, miasto bez wyników, błąd autoryzacji. W każdym przypadku serwer renderuje stronę ze zmienną error zamiast crashować.
EJS — warunkowe renderowanie wyników
<% if (locals.events && locals.events.length > 0) { %>
<section class="eventsList">
<ul>
<% events.forEach((event) => { %>
<li>
<span><%=event.eventName%></span>
<p><%=event.eventDate%></p>
<p><%=event.eventLocation%></p>
<a href="<%=event.eventUrl%>" target="_blank">See more</a>
</li>
<% }); %>
</ul>
</section>
<% } else { %>
<h1><%=error%></h1> <!-- "No events found for this criteria." -->
<% } %>
04Ticketmaster Discovery API
Aplikacja używa publicznego endpointu GET /discovery/v2/events z Ticketmaster API.
Odpowiedź jest zagnieżdżoną strukturą JSON — dane eventi siedzą w response.data._embedded.events,
a dane o miejscu w event._embedded.venues[0]. Operator ?. (optional chaining)
zabezpiecza przed błędem gdy API zwróci odpowiedź bez zagnieżdżonego klucza _embedded
(np. gdy nie ma wyników).
- Filtry daty —
startDateTimeiendDateTimew formacie ISO 8601 UTC, obliczane dynamicznie per request - Filtr miasta — parametr
city, Ticketmaster wyszukuje po nazwie w bazie venue - Klucz API — przekazywany jako parametr
apikeyw URL (standard Ticketmaster) - Odpowiedź — lista wydarzeń z nazwą, datą start, URL do strony biletu, osadzonym venue
05Struktura projektu
data-wait), efekty fadeIn/hide dla komunikatów sukcesu i błędu.background.png jako tło hero sekcji, favicon.png.06Stack technologiczny
express.static() dla plików publicznych, bodyParser dla odczytu danych formularza POST.<%=</code> i pętlami <% forEach >. Zero JS po stronie klienta do budowania UI.axios.get() z automatycznym parsowaniem JSON, obsługą parametrów URL i properly typed response."type": "module" w package.json — nowoczesne import zamiast require() we wszystkich plikach projektu.07Czego dowodzi ten projekt
API integration
Pełny cykl: klucz API → parametry → Axios GET → parsowanie zagnieżdżonego JSON → mapowanie do widoku.
Asynchroniczny Node.js
async/await z blokiem try/catch — właściwa obsługa operacji I/O bez callback hell.
Formatowanie dat UTC
Ręczne budowanie dat ISO 8601 przez UTC gettery — świadomość timezone w API-world.
Optional chaining
_embedded?.events || [] — defensywne programowanie przy niestabilnych strukturach API.
SSR z EJS
Warunkowe renderowanie dwóch stanów (wyniki / błąd) w jednym szablonie bez JS po stronie klienta.
Projekt w 77 liniach
Skoncentrowany scope — jeden cel, minimalny kod, zero over-engineeringu. Działa.
Zobacz kod na GitHubie
77 linii backendu, jeden szablon EJS i integracja z Ticketmaster API — cały projekt w zasięgu wzroku.
Zobacz kod na GitHub