okapi/lib
2023-11-17 02:02:23 -08:00
..
examples Factor out examples to seperate directories 2023-11-17 02:02:23 -08:00
src Factor out examples to seperate directories 2023-11-17 02:02:23 -08:00
test Remove unecessary code; add basic patterns 2023-07-19 19:16:04 +09:00
.gitignore Major refactor 2023-04-20 06:36:55 +00:00
ChangeLog.md Major refactor 2023-04-20 06:36:55 +00:00
HSP.md Major refactor 2023-04-20 06:36:55 +00:00
LICENSE Major refactor 2023-04-20 06:36:55 +00:00
NewDesign.md Update docs; change ResponderHeaders to AddHeader 2023-04-21 05:13:34 +00:00
okapi.cabal Factor out examples to seperate directories 2023-11-17 02:02:23 -08:00
README.md Factor out examples to seperate directories 2023-11-17 02:02:23 -08:00
release.md Change Choose to Choice for consistency 2023-11-12 11:22:40 -08:00
Setup.hs Major refactor 2023-04-20 06:36:55 +00:00

🦓🦒Okapi

Okapi is a data-driven micro framework for implementing HTTP servers.

  • Ergonomic DSLs for routing and parsing requests
  • Integrate Okapi with ANY monad stack or effect system
  • Automatically generate clients and OpenAPI specifications (coming soon)
  • Programatically generate your API's structure

Hello World Example

helloWorld =
  responder @200 @'[] @Text.Text @Text.Text
    . method HTTP.GET id
    $ \greet _req -> return $ greet noHeaders "Hello World!"

main =
  Warp.run 8000
    . withDefault helloWorld
    $ \_ resp -> resp $ Wai.responseLBS HTTP.status404 [] "Not Found..."

Calculator Example

data Operator
    = Add
    | Sub
    | Mul
    | Div
    | Sq
    | Neg
    deriving (Show)

instance Web.FromHttpApiData Operator where
    parseUrlPiece "add" = Right Add
    parseUrlPiece "sub" = Right Sub
    parseUrlPiece "minus" = Right Sub
    parseUrlPiece "mul" = Right Mul
    parseUrlPiece "div" = Right Div
    parseUrlPiece "neg" = Right Neg
    parseUrlPiece "sq" = Right Sq
    parseUrlPiece "square" = Right Sq
    parseUrlPiece _ = Left "Can't parse operator..."

shared =
  lit "calc"
    . param @Operator
    . param @Int

unary =
  responder @200 @'[] @Text.Text @Int
    . responder @500 @'[] @Text.Text @Text.Text
    . method HTTP.GET id

unaryHandler operator x ok wrongArgs _req =
  return $ case operator of
    Sq  -> ok noHeaders (x * x)
    Neg -> ok noHeaders (x * (-1))
    _   -> wrongArgs noHeaders $ Text.pack (show operator) <> " needs two arguments."

binary =
  param @Int
    . responder @200 @'[] @Text.Text @Int
    . responder @500 @'[] @Text.Text @Text.Text
    . responder @403 @'[] @Text.Text @Text.Text
    . method HTTP.GET id

binaryHandler operator x y ok wrongArgs divByZeroErr _req =
  return $ case operator of
    Add -> ok noHeaders (x + y)
    Sub -> ok noHeaders (x - y)
    Mul -> ok noHeaders (x * y)
    Div ->
      if y == 0
      then divByZeroErr noHeaders "You can't divide by 0."
      else ok noHeaders (div x y)
    _ -> wrongArgs noHeaders $ Text.pack (show operator) <> " needs one argument."

calc = shared $ choice
  [ unary unaryHandler
  , binary binaryHandler
  ]

main =
  Warp.run 8003
    . withDefault calc
    $ \_ resp -> resp $ Wai.responseLBS HTTP.status404 [] "Not Found..."