drashland / drash Goto Github PK
View Code? Open in Web Editor NEWA microframework for building JavaScript HTTP applications. Runtime-agnostic. Strongly typed.
Home Page: https://drash.land/drash
License: GNU General Public License v3.0
A microframework for building JavaScript HTTP applications. Runtime-agnostic. Strongly typed.
Home Page: https://drash.land/drash
License: GNU General Public License v3.0
What: Documentation for using deno_mysql
Why:
// Add example pseudo code for implementation
What: Automate docs deployment when tag is pushed.
Why: Running the deploy script locally to deploy the docs to production can be automated and improve the workflow. Travis CI should deploy the docs when a new tag is pushed.
What: Split Drash.Http into its own repository. Import code from new repository.
Why: deno-drash should contain a compilation of modules that are imported from other repositories.
Check the following:
server_test.ts
middleware_test.ts
cookie_resource.ts
Do you have any plan for document to connect the database such as mongodb, mysql etc .. ?
I try some lib of deno to connect mysql such as deno_mysql
but i dont know how to use in resource. Like we can pass the client
as argument of class resource ?
/docs/src/example_code
); follow tutorials to make sure they're still validpage-tutorial-default
component and they need toPages
Describe the bug
When trying to override Drash.Http.Response
, a "read-only" error is thrown.
To Reproduce
Steps to reproduce the behavior:
Run the example app and uncomment line 6.
Expected behavior
Users should be able to overwrite Drash.Http.Response
.
Suggested Solution(s)
Use let
instead of const
in mod.ts
.
What: Drash should have a Loggers
namespace where all loggers can be stored for global use.
Why: Importing the Drash namespace in each file instead of having multiple import lines cleans up the file and creates one way to grab the loggers.
Drash.Loggers.MyCoolLogger.info("Hello!");
Drash.Loggers
namespace. This requires renaming the current Drash.Loggers
namespace.Drash.Loggers
namespace must be unique. An error should be thrown if a logger is added with a duplicate name.addLogger
functionality.Drash.Loggers
namespace is renamed.src/loggers
directory, then the directory list in docs/docs.ts
will need to be updated. There is a compileApiReferencePageData()
function that generates the API Reference page's JSON--using a directory list (a list of directories that it reads through) to find data and store it as JSON.// File: mod.ts
Drash {
...
Loggers: {},
...
addLogger(name: string, logger: any) {
this.Loggers[name] = logger;
}
}
// File: app.ts (where the logger object is defined and added to Drash.Loggers)
import Drash from "https://deno.land/x/drash/mod.ts";
let myLogger = new Drash.Loggers.FileLogger({
enabled: true,
level: "debug"
});
Drash.addLogger("MyLogger", myLogger);
// File: some_file.ts (where the logger object is used--just by importing Drash and referencing Drash.Loggers.MyLogger)
import Drash from "https://deno.land/x/drash/mod.ts";
// Access the MyLogger in the Loggers namespace and write an info log message
Drash.Loggers.MyLogger.info("test");
Request URLs are being parsed with the assumption that they always have a query string. This is wrong. Improve the hydration of HTTP request objects in the Drash.Services.HttpService
class so that the request has the following properties:
url_query_string
url_query_params
url_path
If the URL is localhost:8000/what/the?ok=then
, then following properties will return as follows:
url_query_string
: ok=then
WITHOUT the question mark.url_query_params
: {ok: "then"}
url_path
: /what/the
(include the leading slash)If the URL is localhost:8000/what/the
, then following properties will return as follows:
url_query_string
: null
url_query_params
: {}
url_path
: /what/the
(include the leading slash)If the URL is localhost:8000
, then following properties will return as follows:
url_query_string
: null
url_query_params
: {}
url_path
: /
Resource classes should have the following lifecycle hooks:
hook_beforeRequest()
hook_afterRequest()
hook_beforeRequest()
method should be performed before any request method is called.hook_afterRequest()
method should be performed after any request method is called. This hook should be performed before the response is sent to the client.// File: users_resource.ts
import Drash from "https://deno.land/x/drash/mod.ts";
import AuthService from "/path/to/my/auth_service.ts";
import UserService from "/path/to/my/user_service.ts";
/**
* Export the resource that handles user data.
*/
export default class UsersResource extends Drash.Http.Resource {
/**
* Define this resource's paths
*/
static paths = ["/users"];
/**
* Handle GET requests
*/
public GET() {
try {
this.response.body = UserService.getUsers();
} catch (error) {
this.response.body = "Woops. We couldn't get the list of users for you."
}
return this.response;
}
/**
* Handle DELETE requests
*/
public DELETE() {
let userId = this.request.body.user_id;
try {
UserService.delete(userId);
this.response.body = "User deleted.";
} catch (error) {
this.response.body = "Fail.";
}
return this.response;
}
/**
* Perform the following lifecycle hook before any request is made.
*/
protected hook_beforeRequest() {
if (this.request.method == "DELETE" && !AuthService.currentUser().is("admin")) {
throw new Drash.Exceptions.HttpException(401);
}
}
}
What: Use the media types standard module instead of mime-db.
Why: I didn't know deno had its own media types handler. It uses mime-db. It doesn't make sense to manage mime-db in Drash when it's already managed by deno's standard modules.
Release Date: May 13, 2020
Code freeze: May 1, 2020
Accept
header
import { Drash }
instead of import Drash
Drash.version
Drash.Http.Server.port
await server.run()
What: CI to compile Drash down to JS for portability
Why: Portability is cool.
Describe the bug
When parsing doc blocks for JSON output for the API reference, the doc blocks end up with characters that aren't expected to be matched.
https://regexr.com/ shows that more than what's expected is being matched.
To Reproduce
Steps to reproduce the behavior:
server.ts
into regexr.re_all_members
regex in doc_blocks_to_json.ts
and paste it as the expression in regexr.default export class Server { ....
is being matched.There are also multiple instances of this in doc_blocks_to_json.ts
.
Expected behavior
None of the bodies of the methods/functions should be matched.
Suggested Solution(s)
Parse single line and multi line members separately, then combine them to be parsed altogether.
Deno was updated. Test Drash and support Deno accordingly.
What: Need a DocBlock parser to generate API Reference page(s).
Why: After some investigating, TypeDoc seems to be the best option for generating docs. However, without editing its internals, you can't really parse .ts files (especially Deno-friendly .ts files). Errors are thrown because of linting, errors are thrown because TypeDoc can't find imports, etc. Just make a parser for now until something better and faster comes along.
Parser must output parsed docblocks into JSON. Sample below (it doesn't have to meet the sample's exact spec):
{
"my_cool_class.ts": {
"properties": [
{
"name": "property_one",
"type" "string"
},
{
"name": "property_two",
"type" "boolean"
}
],
"methods": [
{
"name": "MethodOne",
"params": [],
"returns": [
{
"type": "void",
"description": "It just delegates."
}
],
"throws": []
},
{
"name": "MethodTwo",
"params": [
{
"type": "any",
"name": "object",
"description": "The object to use."
},
{
"type": "key",
"name": "key",
"description": "The key to find in the object to use."
}
],
"returns": [
{
"type": "any",
"description": "Returns the value of the key in the object to use."
}
],
"throws": []
}
]
}
}
let files = {
"file.js": {}
}
for (let key in files) {
files[key] = parseDocBlocks(key);
}
parseDocBlocks(file: string) {
// do something
}
parseDocBlock(docBlock: string) {
// do something
}
What: Drash.Sockets.Client
Drash.Sockets.Client
class
Users should be able to add tags to log messages. Examples below:
INFO | some tag | some tag | some tag | The log message.
tag_string
config that defines how the tags are arranged.tag_string_fns
config that defines each tag.tag_string
config is {some_tag}
(with the brackets so they can be replaced easily).{level}
tag is a reserved tag. Specifying a level
key in the tag_string_fns
config does nothing.Example code
The following app ...
// File: app.ts
import Drash from "https://deno.land/x/drash/mod.ts";
let logger = new Drash.Loggers.ConsoleLogger({
enabled: true,
level: "all",
tag_string: "[ {datetime} ] {machine_hostname} | {level} ({hello}) |",
tag_string_fns: {
datetime: function() {
return (new Date()).toISOString();
},
hello: "World",
machine_hostname: "E15"
}
});
logger.info("The application has started");
... passed to the deno
command ...
#!/bin/bash
deno app.ts --allow-write
... should output the following:
[ 2019-03-10T14:22:15.728Z ] E15 | INFO (World) | The application has started.
What: Code should be portable so that it can be used with other runtimes/frameworks/etc. (e.g., Node)
What: Drash.Compilers.TemplateEngine
Why: Template engines are essential to building server-rendered web apps in Drash. Currently, the only template engine that works really well in Deno is dejs. However, it's a third-party module and it's up to the user to implement it. It would be nice for a template engine to already be available in Drash if the user wants to use it.
Drash.Compilers.TemplateEngine
example_app
dirSee https://krasimirtsonev.com/blog/article/Javascript-template-engine-in-just-20-line instructions
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Pages with big blocks of code should not have Prism.js block the main thread. Blocking the main thread causes the page to appear frozen. You can see why this is bad.
Possible Solution(s)
Screenshots
NA
What: Abstract the logic that reads a view file and decodes it into a serpate method that takes a view name.
Why: Simplifies the code the user has to write, resulting i less boilerplate the user has to add. Will result in a single line of code the user has to write, instead of creating a decoder and writing that logic themselves
Logic required to return a view file is handled within a new custom method Drash implements
User should be able to get a views contents with: `this.response.render('/users/add.html', { data })
Update Documentation
** Server constructor would need to check if there's a views_path
if views_renderer
exists **
constructor(...) {
if (configs.views_renderer && !configs.views_path) {
throw an error
}
}
** Server configs would need updating:**
interface ServerConfigs {
...
views_path?: string,
views_renderer?: any
The views path and renderer would need to be passed in to the instantiation of the response class in Drash.Http.Server.handleHttpRequest()
and anywhere else a response
object is created in the server
object
// server.ts
new Drash.Http.Response(request, {
views_renderer: this.configs.views_renderer,
views_path: this.configs.views_path
});
Response class would need to add some extra configuration and a new method
Response {
constructor(request: any, options: any = {}) {
this.request = request;
this.headers = new Headers();
if (options.views_renderer) {
this.renderer = options.views_renderer;
this.views_path = options.views_path; // if there's a views renderer, then there must be a views_path
};
this.headers.set("Content-Type", request.response_content_type);
}
public render(...args) {
args[0] = this.views_path += args[1];
return this.renderer(...args);
}
}
// app.ts
import { render } from "dejs/mod.ts"; // if the user wants to use dejs
class MyResource extends Drash.Http.Resource {
public GET() {
// Get dejs view with dynamic data
this.response.body = this.response.render("users/add.ejs", {my: "data", goes: "here"});
// get dejs view with no dynamic data
this.response.body = this.response.render("/users/add.dejs")
// get html view with no dynamic data
this.response.body = this.response.render("/users/add.html")
// get html view with dynamic data
this.response.body = this.response.render("/users/add.html", {my: "data", goes: "here"})
return this.response;
}
}
const server = ({
...
views_path: "path/to/views", // can be omitted if not rendering views
views_renderer: render// can be omitted if not rendering views
})
What: Move documentation to new repo
Why: /docs
is growing and the Drash module needs to be lean. It's dumb to have to download the documentation to use the Drash module.
/docs
is removedWhat: All members in the Drash namespace should have a type associations.
Why: Stricter syntax, more explosions when bad code is introduced, better API Reference page output.
This work requires deno-drash-docs to be recompiled. See deno-drash-docs' Workflows for committing changes to deno-drash-docs.
console/tests
)deno-drash
version in package.json
to reflect tag used for this workstaging
branch; verify work https://drash.land/stagingWhat: Add support for middleware.
Why: Most frameworks come with middleware support. Drash should also support this. This will remove the resource lifecycle hooks, but will clean up the process. For example, middleware will help unify resources that would share the same lifecycle hook logic.
// Resource
import Drash from "https://deno.land/x/drash/mod.ts";
import MiddlewareOne from "./middleware/middleware_one.ts";
import MiddlewareTwo from "./middleware/middleware_two.ts";
export default class MyResource extends Drash.Http.Resource {
static paths = ["/"];
static middleware = [MiddlewareOne, MiddlewareTwo];
public GET() {
this.response.body = "GET request received!";
return this.response;
}
}
// Server configuration
import Drash from "https://deno.land/x/drash/mod.ts";
import MiddlewareForAllRequestsOne from "./middleware/middleware_for_all_requests_one.ts";
import MiddlewareForAllRequestsTwo from "./middleware/middleware_for_all_requests_two.ts";
import ResourceOne from "./resources/resource_one.ts";
import ResourceTwo from "./resources/resource_two.ts";
let server = new Drash.Http.Server({
address: "localhost:1337",
middleware: [
MiddlewareForAllRequestsOne,
MiddlewareForAllRequestsTwo
],
response_output: "application/json",
resources: [
ResourceOne,
ResourceTwo
]
});
server.run();
What: Importing every route manually in _bundle.js
is getting old. This should be automated using watchmedo
.
Why: Laziness...
watchmedo
starts/restarts the docs server, it should build all of the routes automaticallyimport()
should not be usedNone
What: Automate version bump
Why: Manually updating the version in the docs is annoying.
Describe the bug
When a resource's request method is executing code and that code suddenly throws an error, the Drash server shows a "405 Method Not Allowed" response. Clearly, the method exists, but for some reason the error being thrown in the method is being thrown as a 405.
To Reproduce
Steps to reproduce the behavior:
// file: app.ts
import Drash from "https://deno.land/x/drash/mod.ts";
class HomeResource extends Drash.Http.Resource {
static paths = [
"/"
];
public GET() {
let contents = JSON.parse(decoder.decode(Deno.readFileSync("./somefile.ext")));
this.response.body = contents;
return this.response;
}
}
let server = new Drash.Http.Server({
address: "localhost:1337",
response_output: "application/json",
resources: [HomeResource],
});
server.run();
$ deno --allow-net --allow-read --allow-env app.ts
localhost:1337
Expected behavior
A 500 error should be thrown and the error message from the erroneous code should be displayed.
Please view https://github.com/drashland/deno-drash/blob/master/DEV.md before starting.
What: Handle redirects
Why: Currently, Drash doesn't have any type of redirect feature. Although users can send a response with a redirect status code, it'd be much more convenient if the server handled that for them.
server.redirect
should redirect to the specified location with the specified status code (see below)server.redirect(httpStatusCode: number, location: string) { ... }
What: Use GitHub Actions
Why: I think it's better to manage the CI process through GitHub since the code is here.
console/tests
version: drash v0.28.2
error: Uncaught TypeError: Cannot read property 'byteLength' of undefined
► bufio.ts:123:35
123 let rr: number | Deno.EOF = p.byteLength;
What:
In #99, revising of the Content Negotiation docs revealed that the logic to get the Response-Content-Type header from the request happens in the response and doesn't make sense for it to be that way.
Why:
If a resource is responsible for determining its representation based on the request, then it should get that information from the request and not the response. The response already gets this information from the request, so we're just making the getting of that information uniform.
response_content_type
property.Drash.Services.HttpService
.Whether the framework lacks a verification layer, and whether to consider supporting such writing methods as decorator pattern in the future
What: Drash.Sockets.Server
Drash.Sockets
Drash.Sockets.Server
class
This is probably something already being worked on and i am probably just nagging but deno v0.36.0 and v0.37.0 support would be nice to have. Currently when i tried to upgrade the dependencies failing in the old version it failed at the following test: missing CSRF token
and errored at the following test wrong CSRF token
(#138). When running the example everything seemed to work fine otherwise.
Please view https://github.com/drashland/deno-drash/blob/master/DEV.md before starting.
What: Handle cookies.
Why: Cookies are part of the request-resource-response lifecycle, but the Drash server doesn't handle them yet.
Cookie
interface that Deno has definedthis.server.getCookie()
and this.server.setCookie()
.HttpRequestService
should be the class that handles parsing cookies; and resources should be able to call this.request.getCookie()
or something similar that makes sensethis.response.setCookie()
or something similar that makes sense)api_reference.json
file and update deno-drash-docs
to use it.server.setCookie();
server.getCookie();
The methods above should implement https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies as closely as possible
What: Import crookse/drash code
Why: crookse/drash code will contain all of the core and common logic that's used to create the deno-drash microframework. It's written in TS, compiled to JS, and can be used in any JS platform.
Describe the bug
When a resource specifies paths with and without path params and check for those path params regardless if they're present, then the following error could occur:
"Cannot read property '{the_path_param}' of undefined"
To Reproduce
Steps to reproduce the behavior:
Load the following resource in a Drash server and make a GET /
request.
import Drash from "https://deno.land/x/drash/mod.ts";
export default class HomeResource extends Drash.Http.Resource {
static paths = [
"/",
"/:something"
];
public GET() {
this.response.body = "GET request received!";
let pathParam = this.request.getPathParam("something");
if (pathParam) {
this.response.body += ` Path param "${pathParam}" received!`;
}
let queryParam = this.request.getQueryParam("something");
if (queryParam) {
this.response.body += ` URL query param "${queryParam}" received!`;
}
let bodyParam = this.request.getBodyParam("something");
if (bodyParam) {
this.response.body += ` Body param "${bodyParam}" received!`;
}
let headerParam = this.request.getHeaderParam("Something");
if (headerParam) {
this.response.body += ` Header param "${headerParam}" received!`;
}
return this.response;
}
}
Expected Behavior
request.path_params = {}
should be the default
Actual Behavior
request.path_params
doesn't exist if a resource doesn't specify any path params
Suggested Solution(s)
request.path_params = {}
should be the default
In Part 2 of the Tutorial, an override of Drash.Http.Response
is introduced with member method of async generateHtmlResponse()
.
class Response extends Drash.Http.Response {
public async generateHtmlResponse(): Promise<any> {
const path = Deno.cwd() + "/src/index.ejs"
const rawOutput = await renderFile(path, {body: this.body});
const html = rawOutput.toString();
return html;
}
}
Drash.Http.Response = Response;
The problem arises when Drash.Http.Response.send()
calls Drash.Http.Response.generateResponse()
which invokes the overriden function Response.generateHtmlResponse()
without await
ing it:
// deno-drash/http/response.ts
public send(): any {
let body = this.generateResponse(); // <--- returns a promise, should be awaited
let output = {
status: this.status_code,
headers: this.headers,
body: new TextEncoder().encode(body) // <-- ERR! trying to encode `Promise {}`
};
this.request.respond(output);
return output;
}
Which causes it to crash:
Deno server started at localhost:1337.
Request received: GET /
Calling HomeResource.GET() method.
Sending response. Content-Type: text/html. Status: 200 (OK).
Error occurred while handling request: GET /
Sending response. Content-Type: text/html. Status: 500 (Internal Server Error).
Uncaught TypeError: input is not iterable
at stringToCodePoints (js/text_encoding.ts:51:19)
at encode (js/text_encoding.ts:456:36)
at send (file:///Users/lwong/Library/Caches/deno/deps/https/raw.githubusercontent.com/crookse/deno-drash/v0.7.8/src/http/response.ts:184:31)
at handleHttpRequestError (file:///Users/lwong/Library/Caches/deno/deps/https/raw.githubusercontent.com/crookse/deno-drash/v0.7.8/src/http/server.ts:281:21)
at handleHttpRequest (file:///Users/lwong/Library/Caches/deno/deps/https/raw.githubusercontent.com/crookse/deno-drash/v0.7.8/src/http/server.ts:207:21)
at run (file:///Users/lwong/Library/Caches/deno/deps/https/raw.githubusercontent.com/crookse/deno-drash/v0.7.8/src/http/server.ts:330:12)
Follow the tutorial with the [email protected]
and [email protected]
Overriding generateHtmlResponse
with an async
function should work
package | version |
---|---|
deno |
0.3.7 |
deno-drash |
0.7.8 |
dejs |
0.2.0 |
provide a default path capability for a bare static_paths request or way to extend the resource
What: Explain ...
if a bare request is done for a configured static path ie '/app' with a default ie 'index.html' it should serve the default ie /app/index.html
Why: Explain ...
serve app with a pretty url http://domain.tld/app
at the moment static paths can't be configured like other resources, but it should behave like this and also still serve the other static resources
export class StaticResource extends Drash.Http.Resource {
static paths = ['/app'];
public GET() {
try {
const raw = Deno.readFileSync(`./app/index.html`);
this.response.body = new TextDecoder().decode(raw);
return this.response;
} catch (error) {
throw new Drash.Exceptions.HttpException(400, 'index error');
}
}
}
What: Improve the workflow of bumping version numbers in the codebase.
What: Manually entering the example code data is annoying.
Why: The tools exist to make this automatic just like the vue-router's routes. Also... laziness.
example_code
automaticallyWhat: Currently, the Drash.addMember()
function adds a new member to the Drash.Vendor
namespace. The namespace should be Drash.Members
.
Why: Semantics.
Drash.Members.MyMember
None.
Describe the bug
A test doesn't seem to close the mock server, so it fails when running the next test as the address is in use, see below for the error:
S D:\Development\environments\deno-drash> deno test --allow-env --allow-net .\tests\unit\http\middleware_test.ts
Compile file:///D:/Development/environments/deno-drash/.deno.test.ts
running 12 tests
middleware.ts
OK - (0.00ms)
Deno server started at localhost:1557.
OK server/resource: missing CSRF token (24.00ms)
Deno server started at localhost:1557.
error: Uncaught AddrInUse: Only one usage of each socket address (protocol/network address/port) is normally permitted. (os error 10048)
► $deno$/dispatch_json.ts:40:11
at DenoError ($deno$/errors.ts:20:5)
at unwrapResponse ($deno$/dispatch_json.ts:40:11)
at sendSync ($deno$/dispatch_json.ts:67:10)
at listen ($deno$/net.ts:170:15)
at serve (server.ts:492:20)
at run (server.ts:418:24)
at middleware_test.ts:49:10
at runTests ($deno$/testing.ts:157:22)
It passes the first test, and fails the second, which helps confirm the server hasn't actually closed yet
To Reproduce
Steps to reproduce the behavior:
deno test --allow-env --allow-net .\tests\unit\http\middleware_test.ts
Expected behavior
Tests should be able to run after one another and the mock server should be closed before running the next text (which is also creating a mock server)
Suggested Solution(s)
Couldn't say, maybe there's a race condition or server.deno_server.close();
isn't working as expected
Desktop (please complete the following information):
deno 0.33.0
v8 8.1.108
typescript 3.7.2
Additional context
Disocvered this problem whilst developing the solution to issue #115 types for all members when I tried testing. I tested on a branch without any of my changes and the error still showed
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
/
URI with a GET
method.GET
method, set the response to return an image (any image).Expected behavior
Drash.Http.Server
should be able to send images with the correct MIME type and images should show up in the browser if they exist.
Suggested Solution(s)
Check out how the contents of the image are being read in Drash.Http.Response.sendStatic()
and see if any special-case encoding/decoding needs to happen.
What: Access to this.request.body
.
Why: this.request.url_query_params
, this.request.path_params
, and this.request.body
should all be accessible to find HTTP variable values.
this.request.body
should be accessible in all members that have access to the request object.How to catch the exceptions of the framework? I want to handle the exception information myself
What:
Add unit tests for example apps in the docs. The example apps are the code blocks in the the tutorials.
Why:
Currently, the only tests run for the example apps in the docs are manual tests. There's no for sure way to know that the example code works with changes from Deno and changes from Drash unless each app is run manually. Also, it's a maintenance nightmare waiting to happen.
Describe the bug
The server logger is not accessible from the resource class. For example, calling this.server.logger.debug("some debug message.")
in a resource class will throw Property 'logger' is protected and only accessible within class 'Server' and its subclasses.
To Reproduce
Steps to reproduce the behavior:
Run the following app:
import Drash from "https://deno.land/x/drash/mod.ts";
class HomeResource extends Drash.Http.Resource {
static paths = ["/"];
public GET() {
this.server.logger.fatal("This is a FATAL log message.");
this.server.logger.error("This is an ERROR log message");
this.server.logger.warn("This is a WARN log message");
this.server.logger.info("This is an INFO log message");
this.server.logger.debug("This is a DEBUG log message");
this.server.logger.trace("This is a TRACE log message");
this.response.body = "GET request received!";
return this.response;
}
}
let server = new Drash.Http.Server({
address: "localhost:1337",
response_output: "application/json",
resources: [HomeResource],
logger: new Drash.Loggers.ConsoleLogger({
enabled: true,
level: "all"
})
});
server.run();
Expected behavior
this.server.logger
should be accessible.
Suggested Solution(s)
Make logger
property in Drash.Http.Server
public
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.