Initial commit with basic functionality and library structure.
This commit is contained in:
commit
17d39fcdc2
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/output
|
||||
/.pulp-cache/
|
||||
/.psc*
|
||||
/.purs*
|
||||
/.psa*
|
58
CONTRIBUTING.md
Normal file
58
CONTRIBUTING.md
Normal file
@ -0,0 +1,58 @@
|
||||
# HTTPure Contributing Guide
|
||||
|
||||
Welcome to HTTPure! We would love contributions from the community. Please
|
||||
follow this guide when creating contributions to help make the project better!
|
||||
|
||||
## Logging Issues
|
||||
|
||||
If you find a bug or a place where documentation needs to be improved, or if you
|
||||
have a feature request,
|
||||
please
|
||||
[submit an issue](https://github.com/cprussin/purescript-httpure/issues/new)! In
|
||||
issues you submit, please be clear, and preferably have code examples indicating
|
||||
what is broken, needs improvement, or what your requested API should look like.
|
||||
|
||||
## Contributions
|
||||
|
||||
All contributions to this repository should come in the form of pull requests.
|
||||
All pull requests must be reviewed before being merged. Please follow these
|
||||
steps for creating a successful PR:
|
||||
|
||||
1. [Create an issue](https://github.com/cprussin/purescript-httpure/issues/new)
|
||||
for your contribution.
|
||||
2. [Create a fork](https://github.com/cprussin/purescript-httpure) on github.
|
||||
3. Create a branch in your fork for your contribution.
|
||||
4. Add your contribution to the source tree.
|
||||
5. Run the test suite. All tests MUST pass for a PR to be accepted.
|
||||
6. Push your code and create a PR on github. Please make sure to reference your
|
||||
issue number in your PR description.
|
||||
|
||||
Branch all work off the `master` branch. In the future, we will create branches
|
||||
for specific release series, and `master` will be used for the current stable
|
||||
release series.
|
||||
|
||||
### Documentation
|
||||
|
||||
For the most part, HTTPure's documentation is intended to be consumed
|
||||
through [Pursuit](http://pursuit.purescript.org/packages/purescript-httpure). To
|
||||
this end, documentation should mostly be provided inline in the codebase, and
|
||||
should follow the same PR process as other commits.
|
||||
|
||||
We also welcome documentation in the form of guides and examples. These should
|
||||
live in the [docs](docs) directory. Please ensure all guides are written in
|
||||
markdown format, and all examples are fully-functional and implemented as
|
||||
self-contained subdirectories under [docs/examples](docs/examples).
|
||||
|
||||
We try to ensure most examples have corresponding integration tests, both to add
|
||||
additional testing and to ensure that examples we promote remain functional. If
|
||||
you plan to contribute examples, please take a look
|
||||
at [IntegrationSpec.purs](test/HTTPure/IntegrationSpec.purs).
|
||||
|
||||
### Code
|
||||
|
||||
Code should follow existing styles and all code should be accompanied with
|
||||
relevant unit/integration tests. If you fix a bug, write a test. If you write a
|
||||
new feature, write a test.
|
||||
|
||||
All tests MUST pass for your PR to be accepted. If you break a test, either fix
|
||||
the test or fix the code.
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Connor Prussin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
34
Makefile
Normal file
34
Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
PULP := pulp
|
||||
BOWER := bower
|
||||
BOWERJSON := bower.json
|
||||
SRCPATH := ./lib
|
||||
TESTPATH := ./test
|
||||
OUTPUT := ./output
|
||||
BUILD := $(OUTPUT)/build
|
||||
COMPONENTS := $(OUTPUT)/components
|
||||
DOCS := $(OUTPUT)/docs
|
||||
TESTMAIN := HTTPure.HTTPureSpec
|
||||
SOURCES := $(SRCPATH)/**/*
|
||||
TESTSOURCES := $(TESTPATH)/**/*
|
||||
.PHONY: clean test
|
||||
|
||||
test: $(BUILD) $(TESTSOURCES)
|
||||
$(PULP) test --src-path $(SRCPATH) --build-path $(BUILD) --main $(TESTMAIN)
|
||||
|
||||
$(BUILD): $(COMPONENTS) $(SOURCES)
|
||||
$(PULP) build --src-path $(SRCPATH) --build-path $(BUILD)
|
||||
touch $(BUILD)
|
||||
|
||||
$(COMPONENTS): $(BOWERJSON)
|
||||
$(BOWER) install
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTPUT)
|
||||
|
||||
$(DOCS): $(COMPONENTS) $(SOURCES)
|
||||
$(PULP) docs --src-path $(SRCPATH)
|
||||
rm -rf $(DOCS)
|
||||
mv generated-docs $(DOCS)
|
||||
|
||||
docs: $(DOCS)
|
||||
build: $(BUILD)
|
52
README.md
Normal file
52
README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# HTTPure
|
||||
|
||||
A purescript HTTP server framework.
|
||||
|
||||
## 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](TODO.md). If you'd like to help us get there
|
||||
quicker, please contribute! To get started, check
|
||||
our [contributing guide](CONTRIBUTING.md).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bower install purescript-httpure
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Module documentation is published
|
||||
on [Pursuit](http://pursuit.purescript.org/packages/purescript-httpure).
|
||||
|
||||
## Quick Start
|
||||
|
||||
TODO
|
||||
|
||||
## Testing
|
||||
|
||||
We have a Makefile that wraps all commands for development. To run the test
|
||||
suite, in the project root run:
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We are open to accepting contributions! Please see
|
||||
the [contributing guide](CONTRIBUTING.md).
|
||||
|
||||
## People
|
||||
|
||||
HTTPure is written and maintained
|
||||
by [Connor Prussin](https://connor.prussin.net).
|
||||
|
||||
We are open to accepting contributions! Please see
|
||||
the [contributing guide](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
24
bower.json
Normal file
24
bower.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "purescript-httpure",
|
||||
"homepage": "",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"output",
|
||||
"test",
|
||||
"bower.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"purescript-prelude": "^3.0.0",
|
||||
"purescript-node-http": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"purescript-psci-support": "^3.0.0",
|
||||
"purescript-spec": "^1.0.0"
|
||||
}
|
||||
}
|
13
lib/HTTPure.purs
Normal file
13
lib/HTTPure.purs
Normal file
@ -0,0 +1,13 @@
|
||||
module HTTPure (
|
||||
module HTTPure.HTTPureM,
|
||||
module HTTPure.Server,
|
||||
module HTTPure.Request,
|
||||
module HTTPure.Response,
|
||||
module HTTPure.Route
|
||||
) where
|
||||
|
||||
import HTTPure.HTTPureM (HTTPureM)
|
||||
import HTTPure.Server (serve)
|
||||
import HTTPure.Request (Request, getURL)
|
||||
import HTTPure.Response (Response, write)
|
||||
import HTTPure.Route (Method(..), Route)
|
13
lib/HTTPure/HTTPureM.purs
Normal file
13
lib/HTTPure/HTTPureM.purs
Normal file
@ -0,0 +1,13 @@
|
||||
module HTTPure.HTTPureM
|
||||
( HTTPureM
|
||||
) where
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Prelude (Unit)
|
||||
import Node.HTTP (HTTP)
|
||||
|
||||
-- | The `HTTPureM` monad represents actions acting over an HTTPure server
|
||||
-- | lifecycle. It is the return type of all route handlers and of the `serve`
|
||||
-- | function. It takes an effects row parameter which enumerates all other
|
||||
-- | side-effects performed while carrying out the server actions.
|
||||
type HTTPureM e = Eff (http :: HTTP | e) Unit
|
25
lib/HTTPure/Request.purs
Normal file
25
lib/HTTPure/Request.purs
Normal file
@ -0,0 +1,25 @@
|
||||
module HTTPure.Request
|
||||
( Request
|
||||
, fromHTTPRequest
|
||||
, getURL
|
||||
) where
|
||||
|
||||
import Node.HTTP (HTTP, Request, requestAsStream, requestURL) as HTTP
|
||||
import Node.Stream (Readable)
|
||||
|
||||
-- | TODO write me
|
||||
type Request e = {
|
||||
httpRequest :: HTTP.Request,
|
||||
stream :: Readable () (http :: HTTP.HTTP | e)
|
||||
}
|
||||
|
||||
-- | TODO write me
|
||||
fromHTTPRequest :: forall e. HTTP.Request -> Request e
|
||||
fromHTTPRequest request = {
|
||||
httpRequest: request,
|
||||
stream: HTTP.requestAsStream request
|
||||
}
|
||||
|
||||
-- | TODO write me
|
||||
getURL :: forall e. Request e -> String
|
||||
getURL request = HTTP.requestURL request.httpRequest
|
28
lib/HTTPure/Response.purs
Normal file
28
lib/HTTPure/Response.purs
Normal file
@ -0,0 +1,28 @@
|
||||
module HTTPure.Response
|
||||
( Response
|
||||
, fromHTTPResponse
|
||||
, write
|
||||
) where
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Node.Encoding (Encoding(UTF8))
|
||||
import Node.HTTP (HTTP, Response, responseAsStream) as HTTP
|
||||
import Node.Stream (Writable, writeString)
|
||||
import Prelude (Unit, bind, pure, unit)
|
||||
|
||||
-- | TODO write me
|
||||
-- | TODO wrap me in a Record so that the HTTP response is accessible
|
||||
type Response e = Writable () (http :: HTTP.HTTP | e)
|
||||
|
||||
-- | TODO write me
|
||||
fromHTTPResponse :: forall e. HTTP.Response -> Response e
|
||||
fromHTTPResponse = HTTP.responseAsStream
|
||||
|
||||
-- | TODO write me
|
||||
--setStatusCode ::
|
||||
|
||||
-- | TODO write me
|
||||
write :: forall e. Response e -> String -> Eff (http :: HTTP.HTTP | e) Unit
|
||||
write response str = do
|
||||
_ <- writeString response UTF8 str (pure unit)
|
||||
pure unit
|
46
lib/HTTPure/Route.purs
Normal file
46
lib/HTTPure/Route.purs
Normal file
@ -0,0 +1,46 @@
|
||||
module HTTPure.Route
|
||||
( Method(..)
|
||||
, Route
|
||||
, RouteHandler
|
||||
) where
|
||||
|
||||
import HTTPure.Request (Request)
|
||||
import HTTPure.Response (Response)
|
||||
import HTTPure.HTTPureM (HTTPureM)
|
||||
|
||||
-- | The available HTTP methods that a Route can service.
|
||||
data Method = All | Get | Post | Put | Delete
|
||||
|
||||
-- | All route handler methods - that is, methods for before hooks, after hooks,
|
||||
-- | or route handlers themselves - have this type signature.
|
||||
type RouteHandler e = Request e -> Response e -> HTTPureM e
|
||||
|
||||
-- | A Route matches a given HTTP Method against a given URL string. The route
|
||||
-- | string's format is inspired by express. When a request comes in that
|
||||
-- | matches the route, the handler is executed against the request and the
|
||||
-- | response.
|
||||
type Route e = {
|
||||
method :: Method,
|
||||
route :: String,
|
||||
handler :: RouteHandler e
|
||||
}
|
||||
|
||||
-- The internal representation of a route. The route is converted from a String
|
||||
-- to a RouteMatcher, which can cheaply match routes and extract params.
|
||||
--type LoadedRoute e = {
|
||||
-- method :: Method,
|
||||
-- route :: RouteMatcher,
|
||||
-- handler :: Request e -> Response e -> HTTPure e
|
||||
--}
|
||||
|
||||
-- The main request handler.
|
||||
|
||||
-- Convert the passed in routes to their internal representation.
|
||||
--loadRoutes :: forall e.
|
||||
-- Array (Route e) ->
|
||||
-- Array (LoadedRoute e)
|
||||
--loadRoutes = map \route -> {
|
||||
-- method: route.method,
|
||||
-- handler: route.handler,
|
||||
-- route: toRouteMatcher(route.route)
|
||||
--}
|
40
lib/HTTPure/Server.purs
Normal file
40
lib/HTTPure/Server.purs
Normal file
@ -0,0 +1,40 @@
|
||||
module HTTPure.Server (
|
||||
serve
|
||||
) where
|
||||
|
||||
import Data.Maybe (Maybe(Nothing))
|
||||
import Data.Traversable (traverse_)
|
||||
import Node.HTTP (Request, Response, ListenOptions, createServer, listen) as HTTP
|
||||
import Node.Stream (end)
|
||||
import Prelude (bind, discard, pure, unit, ($), (==))
|
||||
import Data.Array (filter)
|
||||
|
||||
import HTTPure.Route (Route)
|
||||
import HTTPure.Response (fromHTTPResponse)
|
||||
import HTTPure.Request (fromHTTPRequest, getURL)
|
||||
import HTTPure.HTTPureM (HTTPureM)
|
||||
|
||||
-- | TODO write me
|
||||
handleRequest :: forall e. Array (Route e) -> HTTP.Request -> HTTP.Response -> HTTPureM e
|
||||
handleRequest routes request response = do
|
||||
traverse_ (\route -> route.handler req resp) (filter matching routes)
|
||||
end resp (pure unit)
|
||||
pure unit
|
||||
where
|
||||
req = fromHTTPRequest request
|
||||
resp = fromHTTPResponse response
|
||||
matching = \route -> route.route == getURL req
|
||||
|
||||
-- | TODO write me
|
||||
getOptions :: Int -> HTTP.ListenOptions
|
||||
getOptions port = {
|
||||
hostname: "localhost",
|
||||
port: port,
|
||||
backlog: Nothing
|
||||
}
|
||||
|
||||
-- | TODO write me
|
||||
serve :: forall e. Array (Route e) -> Int -> HTTPureM e -> HTTPureM e
|
||||
serve routes port onStarted = do
|
||||
server <- HTTP.createServer $ handleRequest routes -- $ loadRoutes routes
|
||||
HTTP.listen server (getOptions port) onStarted
|
8
test/HTTPure/HTTPureMSpec.purs
Normal file
8
test/HTTPure/HTTPureMSpec.purs
Normal file
@ -0,0 +1,8 @@
|
||||
module HTTPure.HTTPureMSpec where
|
||||
|
||||
import Prelude (Unit, pure, unit)
|
||||
import Test.Spec (Spec)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
httpureMSpec :: Spec (RunnerEffects ()) Unit
|
||||
httpureMSpec = pure unit
|
13
test/HTTPure/IntegrationSpec.purs
Normal file
13
test/HTTPure/IntegrationSpec.purs
Normal file
@ -0,0 +1,13 @@
|
||||
module HTTPure.IntegrationSpec where
|
||||
|
||||
import Prelude (Unit, ($))
|
||||
import Test.Spec (Spec, describe, pending)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
startsServerSpec :: Spec (RunnerEffects ()) Unit
|
||||
startsServerSpec =
|
||||
pending "starts a server"
|
||||
|
||||
integrationSpec :: Spec (RunnerEffects ()) Unit
|
||||
integrationSpec = describe "integration" $
|
||||
startsServerSpec
|
18
test/HTTPure/RequestSpec.purs
Normal file
18
test/HTTPure/RequestSpec.purs
Normal file
@ -0,0 +1,18 @@
|
||||
module HTTPure.RequestSpec where
|
||||
|
||||
import Prelude (Unit, discard, ($))
|
||||
import Test.Spec (Spec, describe, pending)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
fromHTTPRequestSpec :: Spec (RunnerEffects ()) Unit
|
||||
fromHTTPRequestSpec = describe "fromHTTPRequest" $
|
||||
pending "wraps an HTTP request"
|
||||
|
||||
getURLSpec :: Spec (RunnerEffects ()) Unit
|
||||
getURLSpec = describe "getURL" $
|
||||
pending "returns the URL of the request"
|
||||
|
||||
requestSpec :: Spec (RunnerEffects ()) Unit
|
||||
requestSpec = describe "Request" do
|
||||
fromHTTPRequestSpec
|
||||
getURLSpec
|
23
test/HTTPure/ResponseSpec.purs
Normal file
23
test/HTTPure/ResponseSpec.purs
Normal file
@ -0,0 +1,23 @@
|
||||
module HTTPure.ResponseSpec where
|
||||
|
||||
import Prelude (Unit, discard, ($))
|
||||
import Test.Spec (Spec, describe, pending)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
fromHTTPResponseSpec :: Spec (RunnerEffects ()) Unit
|
||||
fromHTTPResponseSpec = describe "fromHTTPResponse" $
|
||||
pending "wraps an HTTP response"
|
||||
|
||||
setStatusCodeSpec :: Spec (RunnerEffects ()) Unit
|
||||
setStatusCodeSpec = describe "setStatusCode" $
|
||||
pending "sets the status code"
|
||||
|
||||
writeSpec :: Spec (RunnerEffects ()) Unit
|
||||
writeSpec = describe "write" $
|
||||
pending "adds the string to the response output"
|
||||
|
||||
responseSpec :: Spec (RunnerEffects ()) Unit
|
||||
responseSpec = describe "Response" do
|
||||
fromHTTPResponseSpec
|
||||
setStatusCodeSpec
|
||||
writeSpec
|
8
test/HTTPure/RouteSpec.purs
Normal file
8
test/HTTPure/RouteSpec.purs
Normal file
@ -0,0 +1,8 @@
|
||||
module HTTPure.RouteSpec where
|
||||
|
||||
import Prelude (Unit, pure, unit)
|
||||
import Test.Spec (Spec)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
routeSpec :: Spec (RunnerEffects ()) Unit
|
||||
routeSpec = pure unit
|
23
test/HTTPure/ServerSpec.purs
Normal file
23
test/HTTPure/ServerSpec.purs
Normal file
@ -0,0 +1,23 @@
|
||||
module HTTPure.ServerSpec where
|
||||
|
||||
import Prelude (Unit, discard, ($))
|
||||
import Test.Spec (Spec, describe, pending)
|
||||
import Test.Spec.Runner (RunnerEffects)
|
||||
|
||||
handleRequestSpec :: Spec (RunnerEffects ()) Unit
|
||||
handleRequestSpec = describe "handleRequest" $
|
||||
pending "handles the request"
|
||||
|
||||
getOptionsSpec :: Spec (RunnerEffects ()) Unit
|
||||
getOptionsSpec = describe "getOptions" $
|
||||
pending "returns an options object"
|
||||
|
||||
serveSpec :: Spec (RunnerEffects ()) Unit
|
||||
serveSpec = describe "serve" $
|
||||
pending "starts the server"
|
||||
|
||||
serverSpec :: Spec (RunnerEffects ()) Unit
|
||||
serverSpec = describe "Server" do
|
||||
handleRequestSpec
|
||||
getOptionsSpec
|
||||
serveSpec
|
23
test/HTTPureSpec.purs
Normal file
23
test/HTTPureSpec.purs
Normal file
@ -0,0 +1,23 @@
|
||||
module HTTPure.HTTPureSpec where
|
||||
|
||||
import Prelude (Unit, discard, ($))
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Test.Spec (describe)
|
||||
import Test.Spec.Reporter (specReporter)
|
||||
import Test.Spec.Runner (RunnerEffects, run)
|
||||
|
||||
import HTTPure.HTTPureMSpec (httpureMSpec)
|
||||
import HTTPure.RequestSpec (requestSpec)
|
||||
import HTTPure.ResponseSpec (responseSpec)
|
||||
import HTTPure.RouteSpec (routeSpec)
|
||||
import HTTPure.ServerSpec (serverSpec)
|
||||
import HTTPure.IntegrationSpec (integrationSpec)
|
||||
|
||||
main :: Eff (RunnerEffects ()) Unit
|
||||
main = run [ specReporter ] $ describe "HTTPure" do
|
||||
httpureMSpec
|
||||
requestSpec
|
||||
responseSpec
|
||||
routeSpec
|
||||
serverSpec
|
||||
integrationSpec
|
Loading…
Reference in New Issue
Block a user