Fix some documentation issues (#70)
This commit is contained in:
parent
3fd5cf0179
commit
d8eb77d666
7
Makefile
7
Makefile
@ -10,6 +10,9 @@ BOWER := bower
|
||||
NODE := node
|
||||
NPM := npm
|
||||
|
||||
# Options to pass to pulp when building
|
||||
BUILD_OPTIONS := -- --stash --censor-lib --strict
|
||||
|
||||
# Package manifest files
|
||||
BOWERJSON := bower.json
|
||||
|
||||
@ -47,7 +50,7 @@ $(BUILD): $(COMPONENTS) $(SOURCES)
|
||||
$(PULP) build \
|
||||
--src-path $(SRCPATH) \
|
||||
--build-path $(BUILD) \
|
||||
-- --stash --censor-lib --strict
|
||||
$(BUILD_OPTIONS)
|
||||
touch $(BUILD)
|
||||
build: $(BUILD)
|
||||
|
||||
@ -89,7 +92,7 @@ test: $(BUILD) $(TESTSOURCES) $(EXAMPLESOURCES)
|
||||
--include $(EXAMPLESPATH) \
|
||||
--build-path $(BUILD) \
|
||||
--main $(TESTMAIN) \
|
||||
-- --stash --censor-lib --strict
|
||||
$(BUILD_OPTIONS)
|
||||
|
||||
# Launch a repl with all modules loaded
|
||||
repl: $(COMPONENTS) $(SOURCES) $(TESTSOURCES) $(EXAMPLESOURCES)
|
||||
|
25
Readme.md
25
Readme.md
@ -7,14 +7,24 @@
|
||||
|
||||
A purescript HTTP server framework.
|
||||
|
||||
HTTPure is:
|
||||
|
||||
- Well-tested (see our [tests](./test))
|
||||
- Well-documented (see our [documentation](./docs))
|
||||
- Built to take advantage of PureScript language features for flexible and
|
||||
extensible routing
|
||||
- Pure (no `set`, `get`, `use`, etc)
|
||||
|
||||
## Status
|
||||
|
||||
This project is currently an early-stage work in progress. It is not
|
||||
production-ready yet. You can track what's left before it gets production-ready
|
||||
by looking at
|
||||
our [roadmap](https://github.com/cprussin/purescript-httpure/projects). If you'd
|
||||
like to help us get there quicker, please contribute! To get started, check
|
||||
our [contributing guide](Contributing.md).
|
||||
This project is currently fairly stable, but has not reached it's 1.0 release
|
||||
yet. You can track what's left before it gets there by looking at our
|
||||
[roadmap](https://github.com/cprussin/purescript-httpure/projects). The API
|
||||
signatures are _mostly_ stable, but are subject to change before the 1.0 release
|
||||
if there's a good reason to change them.
|
||||
|
||||
If you'd like to help us get to 1.0 quicker, please contribute! To get started,
|
||||
check our [contributing guide](Contributing.md).
|
||||
|
||||
## Installation
|
||||
|
||||
@ -27,10 +37,9 @@ bower install --save purescript-httpure
|
||||
```purescript
|
||||
module Main where
|
||||
|
||||
import Prelude (pure, ($))
|
||||
import Prelude (($))
|
||||
|
||||
import Control.Monad.Eff.Console as Console
|
||||
import Data.StrMap as StrMap
|
||||
import HTTPure as HTTPure
|
||||
|
||||
main :: HTTPure.ServerM (console :: Console.CONSOLE)
|
||||
|
@ -15,11 +15,11 @@ import Node.Stream as Stream
|
||||
|
||||
import HTTPure.HTTPureM as HTTPureM
|
||||
|
||||
-- | The Body type is just sugar for a String, that will be sent or received in
|
||||
-- | the HTTP body.
|
||||
-- | The `Body` type is just sugar for a `String`, that will be sent or received
|
||||
-- | in the HTTP body.
|
||||
type Body = String
|
||||
|
||||
-- | Extract the contents of the body of the HTTP Request.
|
||||
-- | Extract the contents of the body of the HTTP `Request`.
|
||||
read :: forall e. HTTP.Request -> Aff.Aff (HTTPureM.HTTPureEffects e) Body
|
||||
read request = Aff.makeAff \_ success -> do
|
||||
let stream = HTTP.requestAsStream request
|
||||
@ -28,7 +28,7 @@ read request = Aff.makeAff \_ success -> do
|
||||
void $ ST.modifySTRef buf ((<>) str)
|
||||
Stream.onEnd stream $ ST.readSTRef buf >>= success
|
||||
|
||||
-- | Write a body to the given HTTP Response and close it.
|
||||
-- | Write a `Body` to the given HTTP `Response` and close it.
|
||||
write :: forall e. HTTP.Response -> Body -> Eff.Eff (http :: HTTP.HTTP | e) Unit
|
||||
write response body = void do
|
||||
_ <- Stream.writeString stream Encoding.UTF8 body $ pure unit
|
||||
|
@ -17,33 +17,34 @@ import Node.HTTP as HTTP
|
||||
|
||||
import HTTPure.Lookup as Lookup
|
||||
|
||||
-- | The Headers type is just sugar for a StrMap of Strings that represents the
|
||||
-- | set of headers sent or received in an HTTP request or response.
|
||||
-- | The `Headers` type is just sugar for a `StrMap` of `Strings` that
|
||||
-- | represents the set of headers in an HTTP request or response.
|
||||
newtype Headers = Headers (StrMap.StrMap String)
|
||||
|
||||
-- | Given a string, return the matching headers. This search is
|
||||
-- | case-insensitive.
|
||||
-- | Given a string, return the value of the matching header, or an empty string
|
||||
-- | if no match exists. This search is case-insensitive.
|
||||
instance lookupHeaders :: Lookup.Lookup Headers String String where
|
||||
lookup (Headers headers') =
|
||||
Maybe.fromMaybe "" <<< flip StrMap.lookup headers' <<< StringUtil.toLower
|
||||
|
||||
-- | Allow a headers set to be represented as a string.
|
||||
-- | Allow a `Headers` to be represented as a string. This string is formatted
|
||||
-- | in HTTP headers format.
|
||||
instance showHeaders :: Show Headers where
|
||||
show (Headers headers') =
|
||||
StrMap.foldMap showField headers' <> "\n"
|
||||
where
|
||||
showField key value = key <> ": " <> value <> "\n"
|
||||
|
||||
-- | Compare two Headers objects by comparing the underlying StrMaps.
|
||||
-- | Compare two `Headers` objects by comparing the underlying `StrMaps`.
|
||||
instance eqHeaders :: Eq Headers where
|
||||
eq (Headers a) (Headers b) = eq a b
|
||||
|
||||
-- | Get the headers out of a HTTP Request object.
|
||||
-- | Get the headers out of a HTTP `Request` object.
|
||||
read :: HTTP.Request -> Headers
|
||||
read = HTTP.requestHeaders >>> Headers
|
||||
|
||||
-- | Given an HTTP Response and a Headers object, return an effect that will
|
||||
-- | write the Headers to the Response.
|
||||
-- | Given an HTTP `Response` and a `Headers` object, return an effect that will
|
||||
-- | write the `Headers` to the `Response`.
|
||||
write :: forall e.
|
||||
HTTP.Response ->
|
||||
Headers ->
|
||||
@ -51,6 +52,6 @@ write :: forall e.
|
||||
write response (Headers headers') = void $
|
||||
TraversableWithIndex.traverseWithIndex (HTTP.setHeader response) headers'
|
||||
|
||||
-- | Convert an Array of Tuples of 2 Strings to a Headers object.
|
||||
-- | Convert an `Array` of `Tuples` of 2 `Strings` to a `Headers` object.
|
||||
headers :: Array (Tuple.Tuple String String) -> Headers
|
||||
headers = StrMap.fromFoldable >>> Headers
|
||||
|
@ -10,24 +10,33 @@ import Data.Maybe as Maybe
|
||||
import Data.Monoid as Monoid
|
||||
import Data.StrMap as StrMap
|
||||
|
||||
-- | Types that implement the Lookup class can be looked up by some key to
|
||||
-- | Types that implement the `Lookup` class can be looked up by some key to
|
||||
-- | retrieve some value. For instance, you could have an implementation for
|
||||
-- | String (Maybe String) Int where `lookup string index` returns `Just` the
|
||||
-- | character in `string` at `index`, or `Nothing` if `index` is out of bounds.
|
||||
-- | `String (Maybe String) Int` where `lookup s i` returns `Just` the
|
||||
-- | character in `s` at `i`, or `Nothing` if `i` is out of bounds.
|
||||
class Lookup a v k where
|
||||
|
||||
-- | Given some type and a key on that type, extract some value that
|
||||
-- | corresponds to that key.
|
||||
lookup :: a -> k -> v
|
||||
|
||||
-- | !! can be used as an infix operator instead of using the `lookup` function.
|
||||
-- | `!!` is inspired by `!!` in `Data.Array`, but note that it differs from
|
||||
-- | `!!` in `Data.Array` in that the default instance for `Arrays` with `Int`
|
||||
-- | key types is defined on `Arrays` of some members of `Monoids`, and will
|
||||
-- | always return a value and will not return `Maybes`. If the requested index
|
||||
-- | is out of bounds, then this implementation will return `mempty` instead of
|
||||
-- | `Nothing`.
|
||||
infixl 8 lookup as !!
|
||||
|
||||
-- | A default instance of Lookup for an Array of some type of Monoid. Note that
|
||||
-- | this is different from `!!` defined in `Data.Array` in that it does not
|
||||
-- | return a Maybe. If the index is out of bounds, the return value is mempty.
|
||||
-- | A default instance of `Lookup` for an `Array` of some type of `Monoid`.
|
||||
-- | Note that this is different from `!!` defined in `Data.Array` in that it
|
||||
-- | does not return a `Maybe`. If the index is out of bounds, the return value
|
||||
-- | is `mempty`.
|
||||
instance lookupArray :: Monoid.Monoid m => Lookup (Array m) m Int where
|
||||
lookup arr = Maybe.fromMaybe Monoid.mempty <<< Array.index arr
|
||||
|
||||
-- | A default instance of Lookup for a StrMap of some type of Monoid. If the
|
||||
-- | key does not exist in the StrMap, then the return value is mempty.
|
||||
-- | A default instance of `Lookup` for a `StrMap` of some type of `Monoid`. If
|
||||
-- | the key does not exist in the `StrMap`, then the return value is `mempty`.
|
||||
instance lookupStrMap :: Monoid.Monoid m =>
|
||||
Lookup (StrMap.StrMap m) m String where
|
||||
lookup strMap = Maybe.fromMaybe Monoid.mempty <<< flip StrMap.lookup strMap
|
||||
|
@ -20,12 +20,12 @@ data Method
|
||||
| Trace
|
||||
| Patch
|
||||
|
||||
-- | If two Methods are the same constructor, they are equal.
|
||||
-- | If two `Methods` are the same constructor, they are equal.
|
||||
derive instance generic :: Generic.Generic Method
|
||||
instance eq :: Eq.Eq Method where
|
||||
eq = Generic.gEq
|
||||
|
||||
-- | Convert a constructor to a string.
|
||||
-- | Convert a constructor to a `String`.
|
||||
instance show :: Show.Show Method where
|
||||
show Get = "Get"
|
||||
show Post = "Post"
|
||||
@ -37,7 +37,7 @@ instance show :: Show.Show Method where
|
||||
show Trace = "Trace"
|
||||
show Patch = "Patch"
|
||||
|
||||
-- | Take an HTTP Request and return the Method for that request.
|
||||
-- | Take an HTTP `Request` and extract the `Method` for that request.
|
||||
read :: HTTP.Request -> Method
|
||||
read request = case HTTP.requestMethod request of
|
||||
"POST" -> Post
|
||||
|
@ -10,15 +10,15 @@ import Data.Maybe as Maybe
|
||||
import Data.String as String
|
||||
import Node.HTTP as HTTP
|
||||
|
||||
-- | The Path type is just sugar for an Array of String segments that are sent
|
||||
-- | in a request and indicates the path of the resource being requested. Note
|
||||
-- | that this type has an implementation of Lookup for `Int` keys defined by
|
||||
-- | `lookpArray` in `Lookup.purs` because `lookupArray` is defined for any
|
||||
-- | `Array` of `Monoids`. So you can do something like `path !! 2` to get the
|
||||
-- | path segment at index 2.
|
||||
-- | The `Path` type is just sugar for an `Array` of `String` segments that are
|
||||
-- | sent in a request and indicates the path of the resource being requested.
|
||||
-- | Note that this type has an implementation of `Lookup` for `Int` keys
|
||||
-- | defined by `lookupArray` in [Lookup.purs](./Lookup.purs) because
|
||||
-- | `lookupArray` is defined for any `Array` of `Monoids`. So you can do
|
||||
-- | something like `path !! 2` to get the path segment at index 2.
|
||||
type Path = Array String
|
||||
|
||||
-- | Given an HTTP Request object, extract the Path.
|
||||
-- | Given an HTTP `Request` object, extract the `Path`.
|
||||
read :: HTTP.Request -> Path
|
||||
read = HTTP.requestURL >>> split "?" >>> first >>> split "/" >>> nonempty
|
||||
where
|
||||
|
@ -12,17 +12,17 @@ import Data.StrMap as StrMap
|
||||
import Data.Tuple as Tuple
|
||||
import Node.HTTP as HTTP
|
||||
|
||||
-- | The Query type is a StrMap of Strings, with one entry per query parameter
|
||||
-- | in the request. For any query parameters that don't have values
|
||||
-- | (`/some/path?query`), the value in the StrMap for that parameter will be
|
||||
-- | the string "true". Note that this type has an implementation of Lookup for
|
||||
-- | `String` keys defined by `lookpStrMap` in `Lookup.purs` because
|
||||
-- | The `Query` type is a `StrMap` of `Strings`, with one entry per query
|
||||
-- | parameter in the request. For any query parameters that don't have values
|
||||
-- | (`/some/path?query`), the value in the `StrMap` for that parameter will be
|
||||
-- | the string `"true"`. Note that this type has an implementation of `Lookup`
|
||||
-- | for `String` keys defined by `lookpStrMap` in `Lookup.purs` because
|
||||
-- | `lookupStrMap` is defined for any `StrMap` of `Monoids`. So you can do
|
||||
-- | something like `query !! "foo"` to get the value of the query parameter
|
||||
-- | "foo".
|
||||
type Query = StrMap.StrMap String
|
||||
|
||||
-- | The StrMap of query segments in the given HTTP Request.
|
||||
-- | The `StrMap` of query segments in the given HTTP `Request`.
|
||||
read :: HTTP.Request -> Query
|
||||
read =
|
||||
HTTP.requestURL >>> split "?" >>> last >>> split "&" >>> nonempty >>> toStrMap
|
||||
|
@ -15,8 +15,8 @@ import HTTPure.Method as Method
|
||||
import HTTPure.Path as Path
|
||||
import HTTPure.Query as Query
|
||||
|
||||
-- | A Route is a function that takes a Method, a Path, a Query, a Header, and a
|
||||
-- | Body, and returns a Response monad.
|
||||
-- | The `Request` type is a `Record` type that includes fields for accessing
|
||||
-- | the different parts of the HTTP request.
|
||||
type Request =
|
||||
{ method :: Method.Method
|
||||
, path :: Path.Path
|
||||
@ -25,8 +25,8 @@ type Request =
|
||||
, body :: Body.Body
|
||||
}
|
||||
|
||||
-- | Given an HTTP Request object, this method will convert it to an HTTPure
|
||||
-- | Request object.
|
||||
-- | Given an HTTP `Request` object, this method will convert it to an HTTPure
|
||||
-- | `Request` object.
|
||||
fromHTTPRequest :: forall e.
|
||||
HTTP.Request ->
|
||||
Aff.Aff (HTTPureM.HTTPureEffects e) Request
|
||||
|
@ -84,17 +84,17 @@ import HTTPure.Headers as Headers
|
||||
import HTTPure.HTTPureM as HTTPureM
|
||||
import HTTPure.Status as Status
|
||||
|
||||
-- | The ResponseM type simply conveniently wraps up an HTTPure monad that
|
||||
-- | The `ResponseM` type simply conveniently wraps up an HTTPure monad that
|
||||
-- | returns a response. This type is the return type of all router/route
|
||||
-- | methods.
|
||||
type ResponseM e = HTTPureM.HTTPureM e Response
|
||||
|
||||
-- | A response is a status code, headers, and a body.
|
||||
-- | A `Response` is a status code, headers, and a body.
|
||||
data Response = Response Status.Status Headers.Headers Body.Body
|
||||
|
||||
-- | Given an HTTP response and a HTTPure response, this method will return a
|
||||
-- | monad encapsulating writing the HTTPure response to the HTTP response and
|
||||
-- | closing the HTTP response.
|
||||
-- | Given an HTTP `Response` and a HTTPure `Response`, this method will return
|
||||
-- | a monad encapsulating writing the HTTPure `Response` to the HTTP `Response`
|
||||
-- | and closing the HTTP `Response`.
|
||||
send :: forall e. HTTP.Response -> Response -> HTTPureM.HTTPureM e Unit
|
||||
send httpresponse (Response status headers body) = do
|
||||
Status.write httpresponse $ status
|
||||
|
@ -21,18 +21,19 @@ import HTTPure.HTTPureM as HTTPureM
|
||||
import HTTPure.Request as Request
|
||||
import HTTPure.Response as Response
|
||||
|
||||
-- | The ServerM type simply conveniently wraps up an HTTPure monad that
|
||||
-- | returns a Unit. This type is the return type of the HTTPure serve and
|
||||
-- | The `ServerM` type simply conveniently wraps up an HTTPure monad that
|
||||
-- | returns a `Unit`. This type is the return type of the HTTPure serve and
|
||||
-- | related methods.
|
||||
type ServerM e = HTTPureM.HTTPureM e Unit
|
||||
|
||||
-- | The SecureServerM type is the same as the ServerM type, but it includes
|
||||
-- | The `SecureServerM` type is the same as the `ServerM` type, but it includes
|
||||
-- | effects for working with the filesystem (to load the key and certificate).
|
||||
type SecureServerM e = ServerM (fs :: FS.FS | e)
|
||||
|
||||
-- | This function takes a method which takes a request and returns a ResponseM,
|
||||
-- | an HTTP request, and an HTTP response. It runs the request, extracts the
|
||||
-- | Response from the ResponseM, and sends the Response to the HTTP Response.
|
||||
-- | This function takes a method which takes a `Request` and returns a
|
||||
-- | `ResponseM`, an HTTP `Request`, and an HTTP `Response`. It runs the
|
||||
-- | request, extracts the `Response` from the `ResponseM`, and sends the
|
||||
-- | `Response` to the HTTP `Response`.
|
||||
handleRequest :: forall e.
|
||||
(Request.Request -> Response.ResponseM e) ->
|
||||
HTTP.Request ->
|
||||
@ -43,9 +44,9 @@ handleRequest router request response =
|
||||
req <- Request.fromHTTPRequest request
|
||||
EffClass.liftEff $ router req >>= Response.send response
|
||||
|
||||
-- | Given a ListenOptions Record, a function mapping Request to ResponseM, and
|
||||
-- | an HTTPureM containing effects to run on boot, creates and runs a HTTPure
|
||||
-- | server without SSL.
|
||||
-- | Given a `ListenOptions` object, a function mapping `Request` to
|
||||
-- | `ResponseM`, and an `HTTPureM` containing effects to run on boot, creates
|
||||
-- | and runs a HTTPure server without SSL.
|
||||
bootHTTP :: forall e.
|
||||
HTTP.ListenOptions ->
|
||||
(Request.Request -> Response.ResponseM e) ->
|
||||
@ -55,8 +56,8 @@ bootHTTP options router onStarted =
|
||||
HTTP.createServer (handleRequest router) >>= \server ->
|
||||
HTTP.listen server options onStarted
|
||||
|
||||
-- | Given a ListenOptions Record, a path to a cert file, a path to a private
|
||||
-- | key file, a function mapping Request to ResponseM, and an HTTPureM
|
||||
-- | Given a `ListenOptions` object, a path to a cert file, a path to a private
|
||||
-- | key file, a function mapping `Request` to `ResponseM`, and an `HTTPureM`
|
||||
-- | containing effects to run on boot, creates and runs a HTTPure server with
|
||||
-- | SSL.
|
||||
bootHTTPS :: forall e.
|
||||
@ -76,7 +77,7 @@ bootHTTPS options cert key router onStarted = do
|
||||
HTTPS.key := HTTPS.keyString key' <>
|
||||
HTTPS.cert := HTTPS.certString cert'
|
||||
|
||||
-- | Given a port number, return a HTTP.ListenOptions Record.
|
||||
-- | Given a port number, return a `HTTP.ListenOptions` `Record`.
|
||||
listenOptions :: Int -> HTTP.ListenOptions
|
||||
listenOptions port =
|
||||
{ hostname: "localhost"
|
||||
@ -85,9 +86,10 @@ listenOptions port =
|
||||
}
|
||||
|
||||
-- | Create and start a server. This is the main entry point for HTTPure. Takes
|
||||
-- | a port number on which to listen, a function mapping Request to ResponseM,
|
||||
-- | and an HTTPureM containing effects to run after the server has booted
|
||||
-- | (usually logging). Returns an HTTPureM containing the server's effects.
|
||||
-- | a port number on which to listen, a function mapping `Request` to
|
||||
-- | `ResponseM`, and an `HTTPureM` containing effects to run after the server
|
||||
-- | has booted (usually logging). Returns an `HTTPureM` containing the server's
|
||||
-- | effects.
|
||||
serve :: forall e.
|
||||
Int ->
|
||||
(Request.Request -> Response.ResponseM e) ->
|
||||
@ -100,7 +102,7 @@ serve = bootHTTP <<< listenOptions
|
||||
-- | 1. A port number
|
||||
-- | 2. A path to a cert file
|
||||
-- | 3. A path to a private key file
|
||||
-- | 4. A handler method which maps Request to ResponseM
|
||||
-- | 4. A handler method which maps `Request` to `ResponseM`
|
||||
-- | 5. A callback to call when the server is up
|
||||
serve' :: forall e.
|
||||
Int ->
|
||||
|
@ -78,10 +78,10 @@ import Prelude
|
||||
import Control.Monad.Eff as Eff
|
||||
import Node.HTTP as HTTP
|
||||
|
||||
-- | The Status type enumerates all valid HTTP response status codes.
|
||||
-- | The `Status` type enumerates all valid HTTP response status codes.
|
||||
type Status = Int
|
||||
|
||||
-- | Write a status to a given HTTP Response.
|
||||
-- | Write a status to a given HTTP `Response`.
|
||||
write :: forall e.
|
||||
HTTP.Response ->
|
||||
Status ->
|
||||
|
Loading…
Reference in New Issue
Block a user