Endpointy JSON
Połączy Pan/Pani http4s z Circe.
Endpointy JSON to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
JSON przez circe
http4s integruje JSON za pośrednictwem modułu http4s-circe, który łączy kodeki circe z EntityDecoder i EntityEncoder. circe to de facto standardowa funkcyjna biblioteka JSON dla języka Scala.
Definiuje się instancje Encoder i Decoder dla swoich typów, a http4s zajmuje się formatem przesyłanych danych.
// build.sbt
// "org.http4s" %% "http4s-circe" % http4sV
// "io.circe" %% "circe-generic" % circeVAutomatyczne wyprowadzanie kodeków
Za pomocą circe-generic można automatycznie wyprowadzać kodeki przy użyciu deriveEncoder/deriveDecoder albo adnotacji @JsonCodec. Mapują one pola klas przypadków na klucze JSON według nazw.
Wyprowadzanie wymaga kodeków dla typów wszystkich pól, rekurencyjnie.
import io.circe.generic.semiauto._
case class User(id: Int, name: String)
implicit val enc = deriveEncoder[User]
implicit val dec = deriveDecoder[User]EntityEncoder z circe
Import org.http4s.circe.CirceEntityEncoder._ udostępnia niejawną instancję EntityEncoder[F, A] dla każdego A, dla którego istnieje circe Encoder. Następnie Ok(user) serializuje dane do JSON z użyciem application/json.
W procedurach obsługi nie trzeba ręcznie konwertować danych do Json.
import org.http4s.circe.CirceEntityEncoder._
HttpRoutes.of[IO] {
case GET -> Root / "me" => Ok(User(1, "Ada"))
}EntityDecoder z circe
Analogicznie: org.http4s.circe.CirceEntityDecoder._ udostępnia EntityDecoder[F, A] dla każdego A, dla którego istnieje circe Decoder. Następnie req.as[User] analizuje ciało JSON.
Oba importy są dostępne razem pod nazwą CirceEntityCodec._.
import org.http4s.circe.CirceEntityDecoder._
case req @ POST -> Root / "users" =>
req.as[User].flatMap(u => Created(u))Pełne żądanie POST z JSON
Połączenie dekodowania i kodowania pozwala utworzyć przejrzysty endpoint tworzenia: należy przeanalizować przychodzący JSON do typu domenowego, wykonać logikę biznesową, a następnie zakodować wynik z powrotem jako JSON.
Błędy dekodowania są sygnalizowane jako 422 lub 400 przez dekoder circe.
import org.http4s.circe.CirceEntityCodec._
case req @ POST -> Root / "users" =>
for {
in <- req.as[User]
out <- store.create(in)
res <- Created(out)
} yield resInterpolacja json
W przypadku doraźnego tworzenia JSON interpolator napisów json biblioteki circe z io.circe.literal bezpośrednio tworzy wartość Json wraz z interpolowanymi wartościami Scali.
Jest przydatny w przypadku małych odpowiedzi lub danych testowych, gdy nie chce się tworzyć klasy przypadku.
import io.circe.literal._
val body = json"""{ "status": "ok", "count": 3 }"""
Ok(body)Niestandardowe nazwy pól
Gdy klucze JSON różnią się od nazw pól Scali, można wyprowadzić kodek za pomocą Configuration z circe-generic-extras, na przykład dla snake_case, albo napisać kodek ręcznie z użyciem forProduct2.
Dzięki temu kontrakt API jest niezależny od wewnętrznego nazewnictwa.
import io.circe.Encoder
implicit val e: Encoder[User] =
Encoder.forProduct2("user_id", "full_name")(u => (u.id, u.name))Kodowanie list
circe automatycznie udostępnia kodeki dla typów List, Vector, Option i Map, gdy tylko istnieje kodek elementów. Dlatego zwracanie kolekcji działa od razu.
Pusta lista jest kodowana jako [], a None jako nieobecny klucz albo null.
import org.http4s.circe.CirceEntityEncoder._
case GET -> Root / "users" =>
store.all.flatMap(us => Ok(us)) // List[User] -> JSON arrayWalidowanie zdekodowanego JSON
Dekodowanie daje syntaktycznie poprawną wartość, ale za walidację semantyczną odpowiada programista. Po wykonaniu as należy przeprowadzić sprawdzenia, a w przypadku niepoprawnych danych zakończyć działanie za pomocą BadRequest.
Dla przejrzystości warto umieszczać niezmienniki domenowe w inteligentnych konstruktorach zwracających Either.
req.as[User].flatMap { u =>
if (u.name.nonEmpty) Created(u)
else BadRequest("name required")
}Odpowiedzi błędów jako JSON
Warto zwracać błędy strukturalne jako JSON, aby klienci mogli je analizować. Należy zdefiniować klasę przypadku błędu z koderem circe i przekazać ją do odpowiedniego konstruktora statusu.
Spójna struktura błędów znacznie ułatwia korzystanie z API.
case class ApiError(code: String, message: String)
implicit val e = deriveEncoder[ApiError]
BadRequest(ApiError("E_NAME", "name required"))Strumieniowanie JSON
W przypadku dużych kolekcji można strumieniować JSON zamiast buforować całość. jsonEncoderOf wraz z fs2 Stream[F, A] emituje tablicę JSON przyrostowo.
Dzięki temu zużycie pamięci pozostaje stałe dla dużych zbiorów wyników, z wykorzystaniem mechanizmu back-pressure biblioteki fs2.
import org.http4s.circe.streamJsonArrayEncoder
case GET -> Root / "feed" =>
Ok(store.streamAll) // fs2.Stream[IO, Event]Szybkie sprawdzenie
Proszę przypomnieć sobie, który import umożliwia dekodowanie ciała JSON do klasy przypadku.
Podsumowanie
Skonfigurowano JSON za pomocą http4s-circe: wyprowadzono kodeki, zaimportowano CirceEntityCodec i użyto Ok(value) / req.as[A] do pełnej obsługi wejścia i wyjścia JSON.
Obsłużono listy, niestandardowe nazwy pól, strukturalne błędy JSON, a nawet strumieniowane tablice dla dużych danych.
Ucz się Scala dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 39
- Lekcje
- 143
Często zadawane pytania
Czy lekcja „Endpointy JSON” jest bezpłatna?
Tak — pełny tekst „Endpointy JSON” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Co nauczysz się w „Endpointy JSON”?
Połączy Pan/Pani http4s z Circe. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Endpointy JSON”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.