eberfreitas / elm-express / Express.Response

This module allows you to create new responses and manipulate them in order to send them to the client. It tries to simplify the interaction compared with the original Express API by allowing only one way to define things and going to the lowest layers while abstracting some inconsistencies and providing type safety to the response definition.

Types


type Response

The Response type wraps the actual definition of your response. It can appear in two different states:

When you create a new response using the new function, it will be Unlocked by default. You can always lock a response using the lock function.

But why do we need that? Consider that you have a middleware that will check if the user is logged in, and if they are not, you want to redirect to the login page. The middleware will run at the very start of the request cycle and you probably don't want any other parts of your application to change the state of the response if the user needs to be redirected. That is why we lock the response. Once locked, the response's state will never change and whatever your middleware decided to do will be respected.


type Status
    = Continue
    | SwitchingProtocols
    | Processing
    | EarlyHints
    | Ok
    | Created
    | Accepted
    | NonAuthoritativeInformation
    | NoContent
    | ResetContent
    | PartialContent
    | MultiStatus
    | AlreadyReported
    | IMUsed
    | BadRequest
    | Unathorized
    | PaymentRequired
    | Forbidden
    | NotFound
    | MethodNotAllowed
    | NotAcceptable
    | ProxyAuthenticationRequired
    | RequestTimeout
    | Conflict
    | Gone
    | LengthRequired
    | PreconditionFailed
    | PayloadTooLarge
    | URITooLong
    | UnsupportedMediaType
    | RangeNotSatisfiable
    | ExpectationFailed
    | ImATeapot
    | MisdirectedRequest
    | UnprocessableContent
    | ResourceLocked
    | FailedDependency
    | TooEarly
    | UpgradeRequired
    | PreconditionRequired
    | TooManyRequests
    | RequestHeaderFieldsTooLarge
    | UnavailableForLegalReasons
    | InternalServerError
    | NotImplemented
    | BadGateway
    | ServiceUnavailable
    | GatewayTimeout
    | HTTPVersionNotSupported
    | VariantAlsoNegotiates
    | InsufficientStorage
    | LoopDetected
    | NotExtended
    | NetworkdAuthenticationRequired

The Status type describes the possible response statuses that you can send.

Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status


type Redirect
    = MultipleChoices String
    | MovedPermanently String
    | Found String
    | SeeOther String
    | NotModified String
    | TemporaryRedirect String
    | PermanentRedirect String

The Redirect type defines the possible redirection statuses you can use when sending a response.

Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages

Creating responses

new : Response

Creates a new, mostly empty, response. It will have a Ok status and an empty text body. Once created you can manipulate the contents of the response with other functions from this module.

response =
    Express.Response.new

Adding content

text : String -> Response -> Response

Sets a plain text response.

textResponse =
    Express.Response.text "Hello world!" response

json : Json.Encode.Value -> Response -> Response

Sets a JSON response.

jsonResponse =
    Express.Response.text encodedValue response

html : String -> Response -> Response

Sets a HTML response. The HTML should be represented as a string but you can use packages like zwilias/elm-html-string to generate HTML like you would for front-end code. We also include a Html.String.Extra module with elm-express to allow you to create full HTML documents.

There is a full example in the /example folder in the repository/source.

htmlResponse =
    Express.Response.html "<h1>Hello World</h1>" response

status : Status -> Response -> Response

Sets the status of the response.

somethingTerribleHasHappened =
    Express.Response.status Express.Response.InternalServerError response

setHeader : String -> String -> Response -> Response

Sets a header in the response.

newResponse =
    Express.Response.setHeader
        "X-Awesome-Header"
        "Look ma! No JS!"
        oldResponse

Redirecting

redirect : String -> Response -> Response

Makes the response redirect to another URL/path. This will make a simple Found (302) redirect. To use other redirection statuses, use rawRedirect.

Attention: this function locks the response.

redirect =
    Express.Response.redirect "/login" response

rawRedirect : Redirect -> Response -> Response

Makes the response directs to another URL/path using the specified Redirect type you wanna use.

Attention: this function locks the response.

redirect =
    Express.Response.rawRedirect (Express.Response.MovedPermanently "/new-blog/article/123") response

Cookies

setCookie : Express.Cookie.Cookie -> Response -> Response

Sets a cookie with the response. To learn how to create a new cookie visit the docs for Express.Cookie module.

newResponse =
    Express.Response.setCookie myCookie oldResponse

unsetCookie : Express.Cookie.Cookie -> Response -> Response

Deletes a cookie. In order to delete a cookie you must recreate it with the same properties as the original cookie excluding maxAge.

newResponse =
    Express.Response.unsetCookie badCookie oldResponse

Session

setSession : String -> String -> Response -> Response

Sets a new session data.

newResponse =
    Express.Response.setSession "user" userDataAsString oldResponse

unsetSession : String -> Response -> Response

Deletes a session data.

newResponse =
    Express.Response.unsetSession "flashMsg" oldResponse

Manipulating responses

lock : Response -> Response

Locks the response guaranteeing that it can't be changed after this fact.

lockedResponse =
    Express.Response.lock unlockedResponse

withUnlocked : (Response -> a) -> Response -> Maybe a

When manipulating responses it is advised to wrap those manipulations inside the withUnlocked function.

Imagine that you have something expensive to run during a request, but the existing response you are manipulating has been locked. Using the withUnlocked function you guarantee that any manipulation will only be called if the response is unlocked.

newResponse =
    oldResponse
        |> Express.Response.withUnlocked (Express.Response.text "IT WORKS!")
        |> Maybe.withDefault oldResponse

Helpers

send : Express.Request.Request -> Response -> Json.Encode.Value

Helper function to send a response. This is most useful if you still don't have a Conn in place like in middlewares. When you have a Conn you can use Express.Conn.send instead.

Here is how you can use this to create a response command:

cmd =
    Express.Response send request response |> responsePort