Aplikacje w Koa.js są budowane przy pomocy zestawów funkcji zwanych middlewares. Dzięki takiej architekturze jesteśmy w stanie wydzielić logikę do poszczególnych funkcji i korzystać z tych samych funkcji w różnych projektach. Dziś o tym jak tworzyć takie funkcje by było to możliwe, na co uważać przy tworzeniu oraz jak łączyć je z innymi.
Inne wpisy o Koa
Middlewares
To co będziemy określać jako middleware to będzie dowolna funkcja, która została zarejstrowana przy pomocy app.use
. Nasza funkcja powinna przyjmować przynajmniej jeden parametr- zwyczajowo nazywany ctx
(od context), gdzie znajdują się najważniejsze dla nas informacje oraz ustawiamy odpowiedzi na zapytanie. Tak jak wspomniałem w poprzednim wpisie Koa mocno poszła w nowości ze świata JavaScriptu więc mamy tutaj możliwość korzystania z funkcji asynchronicznych oraz awaita.
Context
Najważniejszą rzeczą w każdym middleware jest zmienna ctx
. Jak wspomniałem przechowuje dla nas wszytskie informacje oraz umożliwia tworzenie odpowiedzi na zapytanie. Znajdziemy tam takie pola:
req
ires
- są to natywne obiekty z Node’a - odpowiednioRequest
iResponse
request
- obiektRequest
z Koaresponse
- obiektResponse
z Koaapp
- zawiera referencję do utworzonej aplikacjicookies
- pozwala na pobieranie i ustawianie cookies w aplikacjithrow
- pozwala na rzucenie błęduassert
- pozwala na rzucenie błędu jeśli przekazana wartość nie istnieje
Więcej o błędach i ich obsłudze będzie w innym poście.
Tworzenie własnych middlewares
Najprostszy sposób na stworzenie własnego middleware’a to stworzenie zwykłej funkcji oraz zarejestrowanie jej w aplikacji.
const simpleResponse = (ctx) => {
ctx.body = "Hello World"
ctx.status = 200;
}
app.use(simpleResponse2)
Kiedy tworzymy takie funkcje to chcemy je wykorzystywać w wielu miejscach - warto wtedy dać możliwość ustawiania opcji by można było dopasować funkcję do aktualnych potrzeb.
const simpleResponse = (status) => {
const simpleResponse = (ctx) => {
ctx.body = "Hello World"
ctx.status = status;
}
return simpleResponse;
}
app.use(simpleResponse2(200))
Nawet jeśli nasz middleware nie przyjmuje opcji to jest zalecane aby dalej utrzymywać taką strukturę.
Przechodzenie pomiędzy middlewares
Została ostatnia rzecz jeśli chodzi o middlewares czyli przechodzenie pomiędzy różnymi stworzonymi przez nas funkcjami. Do tej pory mieliśmy zarejestrowany jeden middleware który od razu zwracał odpowiedź na zapytanie - jednak w prawdziwych aplikacjach będziemy ich mieć o wiele więcej. Przy komponowaniu naszych funkcji musimy pamiętać o kilku rzeczach.
Po pierwsze wszystkie funkcje są wywoływane w kolejności w jakiej je rejestrujemy - warto o tym pamiętać ponieważ kolejność czasami może mieć znaczenie.
Następna rzecz to przynajmniej jedna z funkcji powinna ustawiać ciało odpowiedzi - jeżeli więcej niż jedna funkcji to ustawia, to ciało odpowiedzi będzie równe ostatniemu ustawieniu.
Ostatnia rzecz o jakiej warto pamiętać to, że jeśli nasza funkcja nie ustawia odpowiedzi to musimy przejść do kolejnej funkcji. Robimy to przy pomocy drugiego parametru funkcji - next
. Jest to funkcja która odsyła sterowanie do następnego middleware’a.
const simpleResponse = (status) => {
const simpleResponse = (ctx) => {
console.log(3);
ctx.body = "Hello World"
ctx.status = status;
}
return simpleResponse;
}
app.use((ctx, next)=>{
console.log(1)
next();
})
app.use((ctx, next)=>{
console.log(2)
next();
})
app.use(simpleResponse(200))
Po wykonaniu zapytania w konsoli pojawi się po kolei następująca sekwencja
1
2
3
Możemy również odwrócić kolejność wywoływania console.log()
jeśli najpierw wywołamy next()
. W momencie gdy wykonamy wszystkie middlewary to wykonywanie funkcji wraca do poprzednich funkcji i jest wykonywany kod, który pozostał po funkcji next()
. Najlepiej to będzie widać na przykładzie:
const simpleResponse = (status) => {
const simpleResponse = (ctx) => {
console.log(3);
ctx.body = "Hello World"
ctx.status = status;
}
return simpleResponse;
}
app.use((ctx, next)=>{
next();
console.log(1)
})
app.use((ctx, next)=>{
next();
console.log(2)
})
app.use(simpleResponse(200))
Teraz w konsoli będzie następująca sekwencja
3
2
1
Z jednej strony jest to ciekawa opcja, ponieważ jesteśmy w stanie osiagnąć różne rzeczy np.: mierzyć statystyki (np.: czas) dla zapytań. Z drugiej strony debuggowanie może być problematyczne jeśli o tym zapomnimy. To co dzisiaj omówiłem jest najważniejszym elementem Koa i wystarczająca do tworzenia aplikacji. Następnym razem opiszę jak reagować na błędy aplikacji.