aeson-schemas icon indicating copy to clipboard operation
aeson-schemas copied to clipboard

Break up `HasSchemaResult` to not require all constraints when only one is needed

Open dewey92 opened this issue 3 years ago • 3 comments

Describe the bug

First of all, thanks for the amazing plugin 🙂 I just started picking up Haskell for my pet project so my knowledge is pretty limited. So to my understanding, this constraint https://github.com/LeapYear/aeson-schemas/blob/70fc7e2158c4dc2626cbc4ead5998bab126c3ac0/src/Data/Aeson/Schema/Internal.hs#L178 will make sure that every type used in the schema QuasiQuote should always have both FromJSON and ToJSON instance. I think this can be a bit problematic if, for instance, I have a password type that can be parsed but shouldn't be sent over the wire:

data Hash = Plain | Hashed

newtype Password (hash :: Hash) = Password Text

mkPlainPassword :: Text -> Either Text (Password 'Plain)
mkPlainPassword pw
  | T.length pw >= 8 = pure $ Password pw
  | otherwise = Left "Password should be at least 8 chars"

instance FromJSON (Password 'Plain) where
  parseJSON rawPw = do
    pw <- parseJSON rawPw
    case mkPlainPassword pw of
      Right p -> pure p
      Left e -> fail $ T.unpack e

type PasswordPlain = Password 'Plain
type PostNewUser =
  Object
    [schema|
  {
    username: Text,
    email: Text,
    password: PasswordPlain,
    fullname: Text,
  }
|]

At least as far as Servant is concerned, I got a type error saying that Password 'Plain should have ToJSON instance, while PostNewUser is only consumed as a request body and not as a response.

data User = ...

instance ToJSON User where
  toJSON u =
    object
      [ "username" .= user_username u
      , "email" .= user_email u
      , "fullname" .= user_fullname u
      ]

type SignUpAPI = ReqBody '[JSON] PostNewUser :> Post '[JSON] User

server :: Server SignupAPI
server = ...

-- | Error
-- 
--   No instance for (ToJSON (Password 'Plain)) arising from a use of `serve`
app = serve (Proxy @SignUpAPI) server

I'm not sure if this is Servant's specific problem or not, but perhaps you can help me give a clue

Expected behavior

I should be able to define a custom type without having ToJSON instance.

dewey92 avatar Jun 20 '21 09:06 dewey92