HTTP Methods

For a REST API, your service will want to support different verbs/methods. Http4s has a list of all the methods you're familiar with, and a few more.

import cats.effect._
import io.circe.generic.auto._
import io.circe.syntax._
import org.http4s._, org.http4s.dsl.io._
import org.http4s.circe._
case class TweetWithId(id: Int, message: String)
case class Tweet(message: String)

def getTweet(tweetId: Int): IO[Option[TweetWithId]] = ???
def addTweet(tweet: Tweet): IO[TweetWithId] = ???
def updateTweet(id: Int, tweet: Tweet): IO[Option[TweetWithId]] = ???
def deleteTweet(id: Int): IO[Unit] = ???

implicit val tweetWithIdEncoder = jsonEncoderOf[TweetWithId]
// tweetWithIdEncoder: EntityEncoder.Pure[TweetWithId] = org.http4s.EntityEncoder$$anon$1@54ce5593
implicit val tweetDecoder = jsonOf[IO, Tweet]
// tweetDecoder: EntityDecoder[IO, Tweet] = org.http4s.EntityDecoder$$anon$2@5d6f6782

val tweetService = HttpRoutes.of[IO] {
  case GET -> Root / "tweets" / IntVar(tweetId) =>
    getTweet(tweetId)
      .flatMap(_.fold(NotFound())(Ok(_)))
  case req @ POST -> Root / "tweets" =>
    req.as[Tweet].flatMap(addTweet).flatMap(Ok(_))
  case req @ PUT -> Root / "tweets" / IntVar(tweetId) =>
    req.as[Tweet]
      .flatMap(updateTweet(tweetId, _))
      .flatMap(_.fold(NotFound())(Ok(_)))
  case HEAD -> Root / "tweets" / IntVar(tweetId) =>
    getTweet(tweetId)
      .flatMap(_.fold(NotFound())(_ => Ok()))
  case DELETE -> Root / "tweets" / IntVar(tweetId) =>
    deleteTweet(tweetId)
      .flatMap(_ => Ok())
}
// tweetService: HttpRoutes[IO] = Kleisli(
//   run = org.http4s.HttpRoutes$$$Lambda$21885/683693719@4ea31af9
// )

There's also DefaultHead which replicates the functionality of the native implementation of the HEAD route.