thiagobustamante / typescript-rest Goto Github PK
View Code? Open in Web Editor NEWThis is a lightweight annotation-based expressjs extension for typescript.
License: MIT License
This is a lightweight annotation-based expressjs extension for typescript.
License: MIT License
I wanna use this api for all kind of request & response types and I want to render the 'index.hbs' template for the request made to path '/' like this :
@Path('/') export class IndexController { @GET public index(@ContextResponse response: express.Response) { response.render('index', {title: 'Social | Main Page'}); } }
Is it possible?
typescript-rest/src/server-container.ts
Line 137 in b704dbf
Express Middlewares placed after buildServices are never called because of next() function is not called at the end of the handler.
Please add next() function call after this.callTargetEndPoint(serviceClass, serviceMethod, req, res, next);
How would you implement authentication on certain routes?
I'm new to typescript an decorators, is there an example or some kind of best practice for this task?
Is there any annotation for authorize or has a way to custom annotation?
I want to split the @ ROUTES definition file. Is it possible?
Hi guys!
Has anyone ever run a deploy on Heroku?
The build works correctly, but when trying to access the API there is some error that breaks the application.
Hi,
Is there a support for client implementation ?
I would like to be able to declare an interface, annotated for the declaration of the REST API and then :
Also it would be really great for Isomorphic apps, as it would enable to call the same api functions on server and client.
Create a support to register services automatically, avoiding the annoying task to register each service, as previously describe in #21, or in #9.
The approach would be:
Server.loadServices(app, 'lib/controllers/*');
or
Server.loadServices(app, ['lib/controllers/*', '!**/exclude*']);
// includes all controllers, excluding that one which name starts with 'exclude'
or
Server.loadServices(app, 'controllers/*', `${__dirname}/..`]);
// Inform a folder as origin for the patterns
I love using typescript-rest, but wanted to easily be able to secure my routes with JWT tokens so I whipped this up and finally got around to rolling it into a package.
It would be nice if you could add a "Supporting Libraries" or "Useful Tools" section to the already awesome README so others who run into my situation don't have to develop their own.
You can find it at https://www.npmjs.com/package/typescript-rest-jwt
~Jacob
I am using:
Server.passportAuth("jwt", "roles");
and it says
Unknown authentication strategy "jwt"
.
passport.ts
import {ExtractJwt, Strategy, StrategyOptions} from "passport-jwt";
import {JwtUser, JwtUserPayload} from "../middlewares/jwtAuth";
const JWT_SECRET: string = "some-jwt-secret";
const jwtConfig: StrategyOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme("JWT"),
secretOrKey: Buffer.from(JWT_SECRET, "base64"),
};
module.exports = function (passport: any) {
console.log("init jwt auth...");
passport.use("jwt", new Strategy(jwtConfig, (payload: JwtUserPayload, done: (a: null, b: JwtUser) => void) => {
const user: JwtUser = {
id: payload.id,
roles: payload.role.split(","),
};
done(null, user);
}));
passport.serializeUser((user: JwtUser, done: (a: null, b: string) => void) => {
done(null, JSON.stringify(user));
});
passport.deserializeUser((user: string, done: (a: null, b: JwtUser) => void) => {
done(null, JSON.parse(user));
});
passport.authenticate("jwt")
console.log("init jwt done");
};
const passport = require ("passport");
require("./config/passport")(passport);
And of course: this.app.use(passport.initialize());
There's a typo in the name of the class ForbidenError
.
It should be spelled with 2 d
s as ForbiddenError
(see here )
typescript-rest/src/server-errors.ts
Line 33 in 6c78c40
I am trying to get use of the new @Security decorator which has been merged into master, but not released on NPM. Any plans to release a new version very soon?
Hey,
I'm using this https://github.com/othiym23/node-continuation-local-storage as a replacement for deprecated nodejs domain package for passing request context through all callbacks and promises.
In turn, this lib uses 'async-listener', which performs some instrumentation on global.Promise:
https://github.com/othiym23/async-listener/blob/master/index.js#L457
which is a problem, because of the way typescript-rest checks response:
https://github.com/thiagobustamante/typescript-rest/blob/master/src/server-container.ts#L343
I can send you a PR fixing this particular problem by adding "wrappedPromise" to the check, but I feel like there should be a better way of fixing this. Let me know if you want me to create the PR anyway.
Could you please add some documentation on the read me file, on how one might implement some middle-ware or filters?
A good use-case is for someone looking to implement authentication and authorization.
Thanks
Summary:
When using the ES6 as TypeScript target, the compilation will fail.
Example:
import * as rest from "typescript-rest";
Compiler error:
node_modules/@types/es6-promise/index.d.ts(11,15): error TS2300: Duplicate identifier 'Promise'.
node_modules/@types/es6-promise/index.d.ts(42,19): error TS2300: Duplicate identifier 'Promise'.
node_modules/typescript/lib/lib.es6.d.ts(4852,11): error TS2300: Duplicate identifier 'Promise'.
node_modules/typescript/lib/lib.es6.d.ts(5175,11): error TS2300: Duplicate identifier 'Promise'.
node_modules/typescript/lib/lib.es6.d.ts(5342,13): error TS2300: Duplicate identifier 'Promise'.
node_modules/typescript/lib/lib.es6.d.ts(5560,11): error TS2300: Duplicate identifier 'Promise'.
Workaround:
Switch to ES5.
Fix:
Don't include the @types/es6-promise
.
I am testing the @FileParam('file') file: Express.Multer.File
parameter.
I initially set up the server to use multer:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, __dirname + '/resources/');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now());
}
});
this.app.use(multer({storage: storage, dest: __dirname + '/resources/'}).any());
then I use the parmeter in my controller:
public async uploadFike(@FileParam('file') file: Express.Multer.File): Promise<IFileCreation> {
Logger.debug(file) // file is always empty
}
Can I address the file variable after it was uploaded? for me file
is empty. I am new to multer so i don't know if I am missing something...
Hello ! I have a quiet similiar question than here => swagger-api/swagger-codegen#5224 (comment)
And if I try to add more than one @Security() decorator at the method level I get an error "Only one Security decorator allowed in ... {method or className}".
Is there a way to add multiple apikeys ?
I'm adding this framework to the TechEmpower Framework Benchmarks and I need to add a required header--not a header param. Aside from setting these headers at the app
level (where app
is a typeof express.Application
), how can I go about setting these headers at the route level? Say, I have the /plaintext
route that should have a Content-Type
of text/plain
. How can I set this at the route level?
In a usual express app, one can easily add prefix to routes like so:
app.use('/api/v1/', router);
How do I do the same here?
Executing task: tsc -p "/Users/x x x x x/workspace/example/ts-rest/tsconfig.json" <
import * as express from "express";
import {Server, Path, GET, PathParam} from "typescript-rest";
@path("/hello")
class HelloService {
@path(":name")
@get
sayHello( @PathParam('name') name: string): string {
return "Hello " + name;
}
}
let app: express.Application = express();
Server.buildServices(app);
app.listen(3000, function() {
console.log('Rest Server listening on port 3000!');
});
Hi,
First of all, great work!
Is there a way I can inject dependencies into my router (like a repository service for instance)?
More generally can I have instance variable initialized in some way?
Manuel
Could you add .nyc_output
, reports
and node_modules
in ".npmignore"?, now when you download the package all these folders are included
Now, downloaded size is: 1.3MB
Excluding that folders size will be: ~556KB (also excluding "src" folder, size will be ~460KB)
How can I do the following, I have a base class template
class BaseService {
model=any;
constructor(model){
this.model=model;
}
async findAll(body){
return await this.model.find(body);
}
async create(body){
return await this.model.insert(body);
}
}
and a child class
class UserService extends BaseService{
constructor(model){
super(model);
}
}
class BookService extends BaseService{
constructor(model){
super(model);
}
}
How can I generate the documentation of both using the template design template?
in this way if you can, but code is duplicated.
@Path("/users")
class UserService{
@GET
findAll(): Promise<Array<User>> {
//...
}
@POST
create():Promide<User>{}
}
@Path("/books")
class UserService {
@GET
findAll(): Promise<Array<User>> {
//...
}
@POST
create():Promide<User>{}
}
Trying to compile the following:
import * as rest from "typescript-rest";
Will result in:
node_modules/typescript-rest/release/lib/server.d.ts(10,71): error TS2305: Module 'Express' has no exported member 'Multer'.
This looks like a bug in the typings not properly importing Multer. Any ideas?
UC: Implementing an async request.
Desired behavior:
Suggested workaround:
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof BadRequestError){
res.set("Content-Type", "application/json")
res.status(err.statusCode)
res.json({info : err.message, data: err.data});
} else {
next(err);
}
});
This works fine here:
@path("dummy1")
@get
dummy1(): Promise {
return new Promise(function (resolve, reject) {
throw new BadRequestError("Works fine, JSON is sent",{some:"data"});
});
}
But it does not work here:
@path("dummy2")
@get
dummy2(): Promise {
return new Promise(function (resolve, reject) {
setTimeout(()=>{
throw new BadRequestError("error handling not applied",{some:"data"});
},1000);
});
}
I used and adapted the code that I found in the README.md :
In /xx/yy/api-server.class :
const app = express();
const api = express.Router();
Server.loadServices(api, '../../api/*');
this.api.use('api', api);
In /api/*, I have all my decorated services, such as :
@Path('/someResources')
export class SomeResources { ... }
I expected that http://localhost:3000/api/someResources would serve me the service SomeResources, but it does not. It seems that it did not load anything at start ...
Can you help me using this ?
Note that when I import the service and use Server.buildServices()
, the url http://localhost:3000/someResources works perfectly !
@Path('query')
@GET
async getPaged(
@QueryParam('keyword') keyword?: string,
@QueryParam('primary_adviser') primary_adviser?: string,
@QueryParam('secondary_advisers') secondary_advisers?: string,
@QueryParam('intent') intent?: number,
@QueryParam('status') status?: string,
@QueryParam('type') type?: number,
@QueryParam('page') page?: number,
@QueryParam('size') size?: number,
@QueryParam('sort') sort?: string): Promise<PaginateResponse<Customer[]>> {
// here size cannot be null ?
}
I wanna page \ size can be nullable.
for example app.ts
import * as express from 'express';
import { controllers } from './controllers';
import { Server } from 'typescript-rest';
const app: express.Express = express();
app.get('/api', function (req, res) {
res.send('');
});
Server.buildServices(app, ...controllers);
export default app;
https://github.com/microsoft/typescript-node-starter/blob/master/test/app.test.ts
but it seems app exit with nothing.
It'd be really useful to have a middleware decorator that applies to all the sub-routes of a controller class like so:
@Preprocessor(logger)
@Path('/cars')
class Cars {
...
}
Here, logger
applies to all the routes declared inside this class.
This does not seem to be related to #4.
The Basic example fails calling the route with the error:
TypeError: Class constructor HelloService cannot be invoked without 'new'
Target: ES6
Node: v6.9.5
Workaround: Switch to ES5 and include the @types/es6-promise.
I have two services in different files:
src/controllers/v1/test.controller.ts
src/controllers/v2/test.controller.ts
The main path in the services are:
The first one
@path('test/hello/v1')
export class TestController {
@path('')
@post
public async testName(name: string): Promise {
console.log("hello" + name);
return;
}
}
The second one
@path('test/hello/v2')
export class TestController {
@path('')
@post
public async testName(name: string): Promise {
console.log("hello" + name);
return;
}
}
It throws me this error:
node_modules\typescript-rest\dist\decorators.js:1138
throw Error('Can not use more than one body parameter on the same method.');
I've tried many options but the only way to fix it is to do this:
The first one
@path('test/hello')
export class TestController {
@path('v1')
@post
public async testNameV1(name: string): Promise {
console.log("hello" + name);
return;
}
}
The second one
@path('test/hello')
export class TestController {
@path('v2')
@post
public async testNameV2(name: string): Promise {
console.log("hello" + name);
return;
}
}
Must put the end path in the method path name and change the method name. Is it good? Another way to do something like the first option?
Thank you.
I've been try to write a custom decorator using typescript-rest Preprocessor, which is working as expected if I run it in my local.
Here's my code for custom decorator.
import { Preprocessor } from "typescript-rest";
import { ForbiddenError } from "typescript-rest/dist/server-errors";
import { logger } from "../middleware/logger-mw";
const secured = (...args: any[]) =>
async (req: any) => {
if (args && args.length > 0) {
let isPermitted: boolean = false;
logger.info("Verifying The Roles :: " + JSON.stringify(args));
for (const incRole of args) {
for (const authObj of req.headers.currentUser.authorities) {
if (incRole === authObj.authority) {
isPermitted = true;
break;
}
}
if (isPermitted) {
break;
}
}
if (isPermitted) {
logger.info("Roles Permitted To Aceess API :: " + JSON.stringify(args));
} else {
logger.error("Acess Forbiden For Roles :: " + JSON.stringify(args));
throw new ForbiddenError("Access Forbidden For Roles :: " + JSON.stringify(args));
}
}
return req;
};
export const Permission = (...args: any[]) => Preprocessor(secured.apply(null, args));
But as soon as I try run my node application inside docker it gives me below error.
> [email protected] start /usr/src/app
> ts-node src/app.ts
/usr/src/app/node_modules/ts-node/src/index.ts:296
throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
^
TSError: ⨯ Unable to compile TypeScript
src/decorators/Permission.ts (1,10): Module '"/usr/src/app/node_modules/typescript-rest/dist/typescript-rest"' has no exported member 'Preprocessor'. (2305)
at getOutput (/usr/src/app/node_modules/ts-node/src/index.ts:296:15)
at /usr/src/app/node_modules/ts-node/src/index.ts:325:16
at Object.compile (/usr/src/app/node_modules/ts-node/src/index.ts:479:11)
at Module.m._compile (/usr/src/app/node_modules/ts-node/src/index.ts:379:43)
at Module._extensions..js (module.js:663:10)
at Object.require.extensions.(anonymous function) [as .ts] (/usr/src/app/node_modules/ts-node/src/index.ts:382:12)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/usr/src/app/src/controllers/UtilityController.ts:4:1)
at Module._compile (module.js:652:30)
at Module.m._compile (/usr/src/app/node_modules/ts-node/src/index.ts:379:23)
at Module._extensions..js (module.js:663:10)
at Object.require.extensions.(anonymous function) [as .ts] (/usr/src/app/node_modules/ts-node/src/index.ts:382:12)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/usr/src/app/src/controllers/index.ts:4:1)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `ts-node src/app.ts`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2018-08-27T16_39_15_515Z-debug.log
Below is my Dockerfile
# Taking Ubuntu As A Base OS
FROM ubuntu:16.04
#Creating a working directory
WORKDIR /usr/src/app
# Updating the apt repo
RUN rm -rf /var/lib/apt/lists/*
RUN apt-get update
# Installing curl
RUN apt-get install -y curl
#Installing Libfontconfig
RUN apt-get install -y libfontconfig
# Installing nodejs
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y nodejs
# Setting environment profile variable
# ENV profile prod
# copying the package.json and pakcage-lock.json
COPY package*.json ./
RUN apt-get install -y bzip2
# installing modules and their dependency
RUN npm install
# Bundle app source
COPY . .
EXPOSE 3004
CMD ["npm", "start"]
"typescript-rest": "^1.1.1",
v8.10.0
I have the following endpoint:
@Path('/migrate')
@POST
async migrate (req: MigrationMigrateRequest): Promise<MigrationMigrateResponse> {
and no matter what data i send in the request body, req contains an empty object.
I have searched through all of the documentation and I can't determine why this is.
This will not work:
@Path('users')
@AutoWired
export class UsersRest extends BasicEndpoint<UserData>
{
constructor(@Inject protected service: UsersService)
{
super(service);
}
...
Perhaps the problem is in the InternalServer.buildServices method, when it tries to invoke the validateTargetType method. This is comparing a ioc_wrapper with a real target class and it's failling because they definitely are not equal.
Dev version (non-webpacked) works great but when I build a Prod version w/ webpack I keep getting Error: Duplicated declaration for path [/users/cleaners/all], method [1].
. There is only 1 path defined as such so unclear why this is the resulting error.
Stack:
/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:539
throw Error("Duplicated declaration for path [" + resolvedPath + "], method [" + serviceMethod.httpMethod + "].");
^
Error: Duplicated declaration for path [/users/cleaners/all], method [1].
at Function.Error [as resolvePath] (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:539:1)
at Function.resolvePath [as resolveProperties] (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:521:1)
at e.resolveProperties [as buildService] (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:156:1)
at buildService (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:111:1)
at Map.forEach (<anonymous>)
at forEach (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:109:1)
at Map.forEach (<anonymous>)
at e.forEach [as buildServices] (/workdir/app/webpack:/node_modules/typescript-rest/dist/server-container.js:107:1)
at Function.buildServices (/workdir/app/webpack:/node_modules/typescript-rest/dist/server.js:24:1)
at Object.buildServices (/workdir/app/webpack:/release/lib/index.js:32:1)
at call (/workdir/app/webpack:/webpack/bootstrap:19:1)
at __webpack_require__ (/workdir/app/webpack:/webpack/bootstrap:83:1)
at Object.<anonymous> (/workdir/app/webpack:/webpack/bootstrap:83:1)
at Module._compile (internal/modules/cjs/loader.js:654:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
at Module.load (internal/modules/cjs/loader.js:566:32)
at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
at Function.Module._load (internal/modules/cjs/loader.js:498:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:695:10)
at startup (internal/bootstrap/node.js:201:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:516:3)
Little example
@Path('/hello')
class HelloService {
@Path(':name')
@GET
sayHello(@PathParam('name') name: number): string {
return `Hello ${name}`;
}
}
How could I check the parameters if the type is wrong (in the example above, name is number) or a required param is missing and throw e.g. bad request. Any hint, how could I implement that nicely? :)
Further, I would use that information within Swagger/OpenAPI.
Hello, first off, great library!
One issue I am having is, when I POST an object of a certain type, the properties of type "Date" are not deserialized into a Date object, they remain a string.
Example:
@POST
postInputDataSet( @PathParam("jobId") jobId: number, paramSet: InputDataSetEntity):Promise<InputDataSetEntity>
{
console.log(paramSet.beginDate.getDate());
}
this code fails because beginDate is not a Date, but String. Would automatic deserialization of a Date be possible through this library?
Question...
Is there a way to build an endpoint that responds with 400 Bad Request and the following inside of the request response body?
{
"errors": [
{"field": "customParam", "message": "It is wrong" }
]
}
PS Great library, nice work! 👍
Hi @thiagobustamante ,
I've a scenario where I've multiple routes, each one has it's own file. How do I configure the router?
Thanks in advance!
I was able to get swaggerGen to work, as well as normal routes using the @path decorator. However, I'm not able to expose the swagger endpoint using the example in the readme. Wondering if you could tell me what I'm doing wrong? Here is my server setup:
// server.ts
let expressApp: express.Express = express()
middleware.mountMiddleware(expressApp)
Routes.mountRoutes(expressApp, port)
let server = http.createServer(expressApp)
let io = require('socket.io')(server)
sockets.registerSockets(io)
server.listen(port, '0.0.0.0', function () {
console.log('Express started on port ' + port)
})
// middleware.ts
export function mountMiddleware (expressApp) {
// expressApp.use(morgan('combined'))
wlog.log('debug', 'serving from static path ' + serverConfig.publicPath)
expressApp.use('/', express.static(serverConfig.publicPath))
expressApp.use(BodyParser.json())
expressApp.use(cors())
}
// routes.ts
export function mountRoutes (app, port) {
Server.buildServices(app)
wlog.log('debug', 'setting up Server.swagger from cwd: ' + process.cwd())
Server.swagger(app, './swagger/api/swagger/swagger.yaml', '/api-docs', '0.0.0.0:5674', ['http'])
}
GET to http://localhost:5674/api-docs results in ERR_CONNECTION_REFUSED
GET to http://localhost:3000/api-docs (just in case the route was exposed on the same port as the other routes) results in a status 404
node_modules/@types/express-serve-static-core/index.d.ts(32,10): error TS2300: Duplicate identifier 'PathParams'.
node_modules/@types/express-serve-static-core/index.d.ts(34,10): error TS2300: Duplicate identifier 'RequestHandlerParams'.
Please, add example of using async/await with GET
and POST
Hi,
please publish the library on npm with passport implementation.
Thanks
Hi there,
I managed to create a base REST endpoint defined using your library and it worked like a charm. Now I'm inheriting from this base service and try to overload the @get and the @put methods for a specific endpoint that differs only in those methods.
It's working fine for the @get case but it's complaing on the @put where the setup is the same I guess. The error is:
Method is already annotated with @1. You can only map a method to one HTTP verb.
Here a sripped down version of my classes:
abstract BaseService:
`class BaseService {
@path(':id')
@get
public getEntity(@PathParam('id') id: string, @QueryParam('$expand') expand: string): Promise {
... some code
}
@path(':id')
@put
public updateEntity(@PathParam('id') id: string, entity: any): Promise {
... some code
}
}`
The class that extends the previous one:
`@Path('/admin/viewconfig')
export class ViewConfigService extends BaseService {
@path(':id')
@get
public getEntity(@PathParam('id') viewid: string): Promise {
... some coding here... this overloading is working!
}
@path(':id')
@put
public updateEntity(@PathParam('id') viewId: string, entity: any): Promise {
... some code - but this overloading is complaining
}
}`
Do you have any idea why it is working for GET but not for PUT???
Thx in advance...
Hi! Awesome project. Thank you very much for your work
I tried to find boilerplate, but didn't find any. So i made it by myself
But i need help to stabilize and standardize this boilerplate project
typescript-rest-boilerplate
So for now i have some questions:
How can i avoid that and write like "hey take all classes from 'controller' folder and use them as handlers"?
Maybe you have some configuration var or class for such type of behavior?
More questions coming soon....
I'd like to have a middleware, like authorization middleware for example.
How can I use middleware with typescript-rest.
Suppose I have something like this:
app = express();
const myMiddleware = (req, res, next) => {
console.log("I'm in the middle");
next();
}
@Path("/get")
class MyGetController {
@GET
getSomething() {
return "Some response";
}
}
app.use('/api', myMiddleware, MyGetController);
How can I do it? How can I augment a class with some middleware in front of it?
How can I use typescript-rest to write middleware, and to compose middleware with controllers?
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.