Skip to content

Commit

Permalink
added cookie helpers (zio#2439)
Browse files Browse the repository at this point in the history
* added cookie helpers

* a few changes

* fix conflicts

* format

* improvements

* better docs
  • Loading branch information
TomTriple committed Sep 27, 2023
1 parent 8d059cf commit 588ab4f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 3 deletions.
16 changes: 15 additions & 1 deletion docs/dsl/cookies.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,21 @@ It updates the response header `Set-Cookie` as ```Set-Cookie: <cookie-name>=<coo

## Getting Cookie from Request

In HTTP requests, cookies are stored in the `cookie` header. `cookiesDecoded` can be used to get all the cookies in the request:
From HTTP requests, a single cookie can be retrieved with `cookie`.

```scala mdoc
private val app4 =
Routes(
Method.GET / "cookie" -> handler { (req: Request) =>
val cookieContent = req.cookie("sessionId").map(_.content)
Response.text(s"cookie content: $cookieContent")
}
)
```

## Getting Cookie from Header

In HTTP requests, cookies are stored in the `cookie` header.

```scala mdoc
private val app3 =
Expand Down
42 changes: 40 additions & 2 deletions zio-http/src/main/scala/zio/http/Request.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package zio.http
import java.net.InetAddress

import zio.stacktracer.TracingImplicits.disableAutoTrace
import zio.{Trace, ZIO}
import zio.{Chunk, Trace, ZIO}

import zio.http.internal.HeaderOps

Expand Down Expand Up @@ -107,8 +107,46 @@ final case class Request(
def unnest(prefix: Path): Request =
copy(url = self.url.copy(path = self.url.path.unnest(prefix)))

/**
* Returns the cookie with the given name if it exists.
*/
def cookie(name: String): Option[Cookie] =
header(Header.Cookie).map(_.value).flatMap(_.filter(_.name == name).headOption)
cookies.find(_.name == name)

/**
* Uses the cookie with the given name if it exists and runs `f` with the
* cookie afterwards.
*/
def cookieWithZIO[R, A](name: String)(f: Cookie => ZIO[R, Throwable, A])(implicit
trace: Trace,
): ZIO[R, Throwable, A] =
cookieWithOrFailImpl[R, Throwable, A](name)(new java.util.NoSuchElementException(s"cookie doesn't exist: $name"))(f)

/**
* Uses the cookie with the given name if it exists and runs `f` with the
* cookie afterwards.
*
* Also, you can set a custom failure value from a missing cookie with `E`.
*/
def cookieWithOrFail[R, E, A](name: String)(missingCookieError: E)(f: Cookie => ZIO[R, E, A])(implicit
trace: Trace,
): ZIO[R, E, A] =
cookieWithOrFailImpl(name)(missingCookieError)(f)

private def cookieWithOrFailImpl[R, E, A](name: String)(e: E)(f: Cookie => ZIO[R, E, A])(implicit
trace: Trace,
): ZIO[R, E, A] = {
cookie(name) match {
case Some(value) => f(value)
case None => ZIO.fail(e)
}
}

/**
* Returns all cookies from the request.
*/
def cookies: Chunk[Cookie] =
header(Header.Cookie).fold(Chunk.empty[Cookie])(_.value.toChunk)

def flashMessage: Option[String] =
cookie("zio-http-flash").map(_.content)
Expand Down

0 comments on commit 588ab4f

Please sign in to comment.