{"id":13524251,"url":"https://github.com/krpeacock/server","last_synced_at":"2025-04-01T02:31:00.512Z","repository":{"id":160030086,"uuid":"628365844","full_name":"krpeacock/server","owner":"krpeacock","description":"Motoko Http Server (wip)","archived":false,"fork":false,"pushed_at":"2024-08-26T23:43:00.000Z","size":559,"stargazers_count":29,"open_issues_count":1,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-02T08:32:10.651Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://qg33c-4aaaa-aaaab-qaica-cai.ic0.app/","language":"Motoko","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/krpeacock.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-15T18:09:28.000Z","updated_at":"2024-09-05T16:19:29.000Z","dependencies_parsed_at":"2024-08-22T00:12:24.103Z","dependency_job_id":"5de13a4c-8648-45d0-ba4b-26856868ccbd","html_url":"https://github.com/krpeacock/server","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krpeacock%2Fserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krpeacock%2Fserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krpeacock%2Fserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krpeacock%2Fserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krpeacock","download_url":"https://codeload.github.com/krpeacock/server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246572228,"owners_count":20798921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:08.412Z","updated_at":"2025-04-01T02:31:00.151Z","avatar_url":"https://github.com/krpeacock.png","language":"Motoko","funding_links":[],"categories":["Motoko"],"sub_categories":["Libraries / Frameworks"],"readme":"# Server\n\nThis is a simple HTTP server for Motoko. Its interface is designed to be similar to the popular Express.js library for Node.js.\n\nCheck out the [examples](./examples) directory for examples of how to use this library.\n\nLive http_greet example: [https://qg33c-4aaaa-aaaab-qaica-cai.ic0.app/]([https://qg33c-4aaaa-aaaab-qaica-cai.ic0.app/])\n\n# Installation\n\nTo install this library, run the following command:\n\n```bash\nmops add certified-cache\nmops add server\n```\n\nFor more information on how to install and use `mops`, see the [Mops documentation](https://mops.one).\n\n# Usage\n\n## Setting up\n\nRecommendation: use the `http_greet` example as a starting point to have asset support. It includes a lot of boilerplate for the methods, but it will turn your canister into a full asset canister, compatible with the `icx-asset` util used by `dfx` as well as the `@dfinity/assets` npm package.\n\n\u003e Note: chunked assets (\u003e 2mb) are not supported yet. Coming soon.\n\n---\n\nIn order to have a cache that persists across upgrades, you will need to first initialize a stable store for the entries and pass that to the server.\n\nYou can then bind `http_request` and `http_request_update` to the server's `http_request` and `http_request_update` functions.\n\nFinally, you should add the `preupgrade` and `postupgrade` system functions to your actor. These will be called when the actor is upgraded, and will be used to save the cache and prune it.\n\nHere is a basic example of how to set up a server with a cache:\n\n```lua\nimport Server \"mo:server\";\n\nactor {\n    stable var serializedEntries : Server.SerializedEntries = ([], [], [creator]);\n\n    var server = Server.Server({ serializedEntries });\n\n\n    /*\n     * http request hooks\n     */\n    public query func http_request(req : Server.HttpRequest) : async Server.HttpResponse {\n        server.http_request(req);\n    };\n    public func http_request_update(req : HttpRequest) : async HttpResponse {\n        await server.http_request_update(req);\n    };\n\n\n    /*\n     * upgrade hooks\n     */\n    system func preupgrade() {\n        serializedEntries := server.entries();\n    };\n\n    system func postupgrade() {\n        ignore server.cache.pruneAll();\n    };\n}\n```\n\n## Adding routes\n\nAs with the Express.js library, you can add routes to the server using the `get`, `post`, `put`, and `delete` functions.\n\nEach of these functions takes a path and a callback function. The callback function is called when a request is made to the server with a matching path.\n\nThe callback function takes a `Request` object and a `Response` object. The `Request` object contains information about the request, such as the request body, query parameters, and headers. The `Response` object is used to send a response to the client.\n\nHere is an example of how to add a route to the server:\n\n```lua\ntype Request = Server.Request;\ntype Response = Server.Response;\ntype ResponseClass = Server.ResponseClass;\nserver.get(\"/\", func (req : Request, res : ResponseClass) : async Response {\n    res.send({\n        status_code = 200;\n        headers = [(\"Content-Type\", \"text/plain\")];\n        body = Text.encodeUtf8(\"Hello, world!\");\n        streaming_strategy = null;\n        cache_strategy = #default;\n    });\n});\n```\n\nYou can also use `res.json` to send a JSON response:\n\n```lua\nserver.get(\"/api\", func (req : Request, res : ResponseClass) : async Response {\n    res.json({\n        status_code = 200;\n        body = \"{ \\\"hello\\\": \\\"world\\\" }\";\n        cache_strategy = #default;\n    });\n});\n```\n\n## Request and response objects\n\nThe `Request` object contains information about the request, such as the request body, query parameters, and headers.\n\nResponseClass is a class that will register the functions you provide with the server, so that they can be called when there is a cache miss to the provided route.\n\nThe `Response` object is used to send a response to the client.\n\n### Request\n\nThe `Request (ParsedHttpRequest)` object contains the following fields:\n\n- `method (Text)` - The HTTP method of the request\n- `url (URL)` - The parsed URL of the request\n- `headers ([(Text, Text)])` - The headers\n- `body (?Body) ` - The request body, if any\n\nSee ./docs/RequestTypes.mo for more details.\n\n### Response\n\nThe `Response` object contains the following functions:\n\n- `send (HttpResponse) : async ()` - Send a response to the client\n- `json (HttpResponse) : async ()` - Send a JSON response to the client\n\nMore functions will be added in the future.\n\n## How it works\n\nThe server uses a cache to store responses to requests. When a request is made to the server, the server first checks the cache to see if it has a response for that request. If it does, it returns the cached response. If it does not, it calls the callback function for the route and returns the response from the callback function.\n\nSince the cache also handles certification of the responses, any cached responses can be served as http queries over the Internet Computer. This means that the server can be used to serve static files, such as HTML, CSS, and JavaScript.\n\nFor requests that are not cached, the server will upgrade the request to an update, and then call the callback function for the route. The callback function can then make any changes to the state of the actor, and then send a response to the client.\n\n`POST`, `PUT`, and `DELETE` requests are not cached, since they are not idempotent. They will override the `cache_strategy` option to `#noCache` in the response. If you have a use case for caching these requests, please open an issue.\n\n## Examples\n\nSee the `examples` directory for examples of how to use this library. These examples are also available on the Internet Computer as canisters:\n\n- Http Greet: [https://qg33c-4aaaa-aaaab-qaica-cai.ic0.app/]([https://qg33c-4aaaa-aaaab-qaica-cai.ic0.app/])\n\n## Roadmap\n\n- [ ] `PATCH` requests\n- [ ] `path/:id` routes\n- [ ] `path/:id/:id2` routes\n- [ ] `*` selector\n- [ ] `/*` selectors\n- [ ] `path/*` selectors\n- [ ] `*.ext` selectors\n- [x] Asset Canister (`icx-asset` support)\n- [ ] `res.redirect`\n- [ ] `res.sendFile`\n- [ ] `res.download`\n- [ ] `res.render`\n- [ ] `res.sendStatus`\n- [ ] Certification v2 support (fast dynamic queries)\n\n## Reference\n\nBelow are all of the types and functions that are exported by this library, as well as links to where these types are defined.\n\n### Types\n\n- `type HttpRequest = Server.HttpRequest` - [./src/Server.mo](https://github.com/krpeacock/certified-cache/blob/c1f209d14f490f905b7de2a2bd3f917377310675/src/Http.mo#L36)\n- `type HttpResponse = Server.HttpResponse` - [./src/Server.mo](https://github.com/krpeacock/certified-cache/blob/c1f209d14f490f905b7de2a2bd3f917377310675/src/Http.mo#L28)\n- `type Request = Server.Request` - [./src/Server.mo](https://github.com/NatLabs/http-parser.mo/blob/27cba8ed0d39387e0fb660f65909ffe2a7d54413/src/Types.mo#L92)\n- `type Response = Server.Response` - \n  ```\n  {\n    status_code : Nat16;\n    headers : [Http.HeaderField];\n    body : Blob;\n    streaming_strategy : ?Http.StreamingStrategy;\n    cache_strategy : CacheStrategy;\n  };\n  ```\n- `type SerializedEntries = Server.SerializedEntries`\n```\n(\n    [(HttpRequest, (HttpResponse, Nat))],\n    [(AssetTypes.Key, Assets.StableAsset)], \n    [Principal]\n)\n```\n\n### Classes\n\n- Server - the primary export of this library\n- ResponseClass - a class provided during `get`, `post`, `put`, and `delete`, with the following methods: \n    - `send (Response) : async ()`\n    - `json (Response) : async ()`\n\n### Functions\n\nThese functions are used internally by the library, but are also exported for use by other libraries.\n\n- `compareRequests(req1 : HttpRequest, req2 : HttpRequest) : Bool`\n    - Compares two requests to see if they are equal\n- `hashRequest(req : HttpRequest) : Hash.Hash`\n    - Hashes a request\n- `public func encodeRequest(req : HttpRequest) : Blob`\n    - Encodes a request as a blob\n- `public func yieldResponse(b : HttpResponse) : Blob`\n    - Encodes a response as a blob\n\n## Credits\n\nThis project currently copies the `http-parser` library into its source tree. This is because the `http-parser` library is not currently installable as a package on `mops`. Source code is available at https://github.com/NatLabs/http-parser.mo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrpeacock%2Fserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrpeacock%2Fserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrpeacock%2Fserver/lists"}