Skip to content

v0.12.0 (Beta 10.07.2021)

Choose a tag to compare
@mpscholten mpscholten released this 10 Jul 12:26
· 2226 commits to master since this release

A new IHP release with new features and bug fixes. Over 100 commits have been merged since the last release 馃殌

Major Changes

  • Pagination:
    IHP has a new built-in pagination module.

    Given an action like this:

        action PostsAction = do
            posts <- query @Post
                    |> orderBy #createdAt
                    |> fetch
            render IndexView { .. }

    We can paginate our results by adding a call to paginate:

        action PostsAction = do
            (postsQuery, pagination) <- query @Post
                    |> orderBy #createdAt
                    |> paginate
            posts <- postsQuery |> fetch
            render IndexView { .. }

    We also need to change the view:

    module Web.View.Posts.Index where
    import Web.View.Prelude
    data IndexView = IndexView
        { posts :: [Post]
        , pagination :: Pagination -- <---- Pass pagination variable to the view
    instance View IndexView where
        html IndexView { .. } = [hsx|
                {forEach posts renderPost}
            {renderPagination pagination} -- <---- CALL renderPagination

    Here's how the pagination looks like in the view:


    When you're adding a new Controller to your app, you can use the new pagination checkbox to automatically generate the needed code:


  • Job Timeouts:
    You can now configure a timeout for Job Workers:

    instance Job EmailCustomersJob where
        perform EmailCustomersJob { .. } = do
          customers <- query @Customer |> fetch
          forEach customers sendToCustomer
            sendToCustomer customer = sendMail (MarketingMail customer)
        timeoutInMicroseconds = Just $ 1000000 * 60 -- 60 seconds

    See the documentation for details

  • Added function to delete files from the cloud storage
    You can now use removeFileFromStorage to remove uploaded files from S3 or any other configured cloud storage:

    action DeleteUploadedFileAction { uploadedFileId } = do
        uploadedFile <- fetch uploadedFile
        let storedFile = StoredFile
             { path = get #objectPath uploadedFile
             , url = get #url uploadedFile
        removeFileFromStorage storedFile
        deleteRecord uploadedFile
        redirectTo UploadedFilesAction
  • Custom CORS policies
    If you're building APIs with IHP you can now specify a custom CORS policy:

    -- Config.hs
    import qualified Network.Wai.Middleware.Cors as Cors
    config :: ConfigBuilder
    config = do
        option Development
        option (AppHostname "localhost")
        -- The boolean True specifies if credentials are allowed for the request. You still need to set withCredentials on your XmlHttpRequest
        option Cors.simpleCorsResourcePolicy { Cors.corsOrigins = Just (["localhost"], True) }
  • New Helper Function: allEnumValues
    Given a enum defined in the Schema.sql like this:

    CREATE TYPE colors AS ENUM ('yellow', 'red', 'blue');

    you can call allEnumValues to get a list of all the colors:

    let allColors = allEnumValues @Color
    -- allColors = [ Yellow, Red, Blue ]

    This also works if you define custom type in Web/Types.hs that is deriving Enum:

    data Color = Yellow | Red | Blue deriving (Enum)
    let allColors = allEnumValues @Color
    -- allColors = [ Yellow, Red, Blue ]
  • Respond with XML in your action:

    We added a renderXml function:

    action MyVeryEnterprisyAction = do
        renderXml "<xml></xml>"
  • Added support for Unique Indices

    You can now use CREATE UNIQUE INDEX statements inside your Schema.sql:

    CREATE UNIQUE INDEX users_index ON users (user_name);

Other Changes


See the for upgrade instructions.

If you have any problems with updating, let us know on the IHP forum.

馃摟 To stay in the loop, subscribe to the IHP release emails. Or follow digitally induced on twitter.