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:

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.