GithubHelp home page GithubHelp logo

slanatech / swagger-stats Goto Github PK

View Code? Open in Web Editor NEW
871.0 20.0 136.0 40.12 MB

API Observability. Trace API calls and Monitor API performance, health and usage statistics in Node.js Microservices.

Home Page: https://swaggerstats.io/

License: MIT License

JavaScript 99.43% HTML 0.57%
statistics metrics api swagger rest performance nodejs microservices prometheus grafana

swagger-stats's Introduction

swagger-stats

swagger-stats | API Observability

CircleCI Coverage Status npm version npm downloads Gitter

Trace API calls and Monitor API performance, health and usage statistics in Node.js Microservices

Express, Fastify, Koa, Hapi, Restify

swagger-stats traces REST API requests and responses in Node.js Microservices, and collects statistics per API Operation. swagger-stats detects API operations based on express routes. You may also provide Swagger (Open API) specification, and swagger-stats will match API requests with API Operations defined in swagger specification.

swagger-stats exposes statistics and metrics per API Operation, such as GET /myapi/:parameter, or GET /pet/{petId}

Built-In API Telemetry

swagger-stats provides built-in Telemetry UX, so you may enable swagger-stats in your app, and start monitoring immediately, with no infrastructure requirements. Navigate to http://<your app host:port>/swagger-stats/

swagger-stats Built-In Telemetry

API Analytics with Elasticsearch and Kibana

swagger-stats stores details about each request/response in Elasticsearch, so you may use Kibana to perform detailed analysis of API usage over time, build visualizations and dashboards

swagger-stats Kibana Dashboard

See dashboards/elastic6 for swagger-stats Kibana visualizations and dashboards

Monitoring and Alerting with Prometheus and Grafana

swagger-stats exposes metrics in Prometheus format, so you may use Prometheus and Grafana to setup API monitoring and alerting

swagger-stats Prometheus Dashboard

See dashboards/prometheus for swagger-stats Grafana dashboards

With statistics and metrics exposed by swagger-stats you may spot problematic API endpoints, see where most of errors happens, catch long-running requests, analyze details of last errors, observe trends, setup alerting.

swagger-stats provides:

  • Metrics in Prometheus format, so you may use Prometheus and Grafana to setup API monitoring and alerting
  • Storing details about each API Request/Response in Elasticsearch, so you may use Kibana to perform analysis of API usage over time, build visualizations and dashboards
  • Built-in API Telemetry UI, so you may enable swagger-stats in your app, and start monitoring right away, with no additional tools required
  • Exposing collected statistics via API, including:
  • Counts of requests and responses(total and by response class), processing time (total/avg/max), content length(total/avg/max) for requests and responses, rates for requests and errors. This is baseline set of stats.
  • Statistics by Request Method: baseline stats collected for each request method
  • Timeline: baseline stats collected for each 1 minute interval during last 60 minutes. Timeline helps you to analyze trends.
  • Errors: count of responses per each error code, top "not found" resources, top "server error" resources
  • Last errors: request and response details for the last 100 errors (last 100 error responses)
  • Longest requests: request and response details for top 100 requests that took longest time to process (time to send response)
  • Tracing: Request and Response details - method, URLs, parameters, request and response headers, addresses, start/stop times and processing duration, matched API Operation info
  • API Statistics: baseline stats and parameter stats per each API Operation. API operation detected based on express routes, and based on Swagger (Open API) specification
  • CPU and Memory Usage of Node process

How to Use

Install

npm install swagger-stats --save

If you haven't added prom-client already, you should do this now. It's a peer dependency of swagger-stats as of version 0.95.19.

npm install prom-client@12 --save

Enable swagger-stats middleware in your app

Express

const swStats = require('swagger-stats');
const apiSpec = require('swagger.json');
app.use(swStats.getMiddleware({swaggerSpec:apiSpec}));

Fastify

const swStats = require('swagger-stats');
const apiSpec = require('swagger.json');

const fastify = require('fastify')({
    logger: true
});

// Enable swagger-stats
fastify.register(require('fastify-express')).then(()=>{
    fastify.register(swStats.getFastifyPlugin, {swaggerSpec:apiSpec});
});

Koa

express-to-koa can be used which is just a simple Promise wrapper.

const swStats = require('swagger-stats');
const apiSpec = require('swagger.json');
const e2k = require('express-to-koa');
app.use(e2k(swStats.getMiddleware({ swaggerSpec:apiSpec })));

Hapi

const swStats = require('swagger-stats');
const swaggerSpec = require('./petstore.json');

const init = async () => {

    server = Hapi.server({
        port: 3040,
        host: 'localhost'
    });

    await server.register({
        plugin: swStats.getHapiPlugin,
        options: {
             swaggerSpec:swaggerSpec
        }
    });

    await server.start();
    console.log('Server running on %s', server.info.uri);
};

Restify

const restify = require('restify');
const swStats = require('swagger-stats');
const apiSpec = require('swagger.json');

const server = restify.createServer();

server.pre(swStats.getMiddleware({
    swaggerSpec:apiSpec,
}));

See /examples for sample apps

Get Statistics with API

$ curl http://<your app host:port>/swagger-stats/stats
{
  "startts": 1501647865959,
  "all": {
    "requests": 7,
    "responses": 7,
    "errors": 3,
    "info": 0,
    "success": 3,
    "redirect": 1,
    "client_error": 2,
    "server_error": 1,
    "total_time": 510,
    "max_time": 502,
    "avg_time": 72.85714285714286,
    "total_req_clength": 0,
    "max_req_clength": 0,
    "avg_req_clength": 0,
    "total_res_clength": 692,
    "max_res_clength": 510,
    "avg_res_clength": 98,
    "req_rate": 1.0734549915657108,
    "err_rate": 0.4600521392424475
  },
  "sys": {
    "rss": 59768832,
    "heapTotal": 36700160,
    "heapUsed": 20081776,
    "external": 5291923,
    "cpu": 0
  },
  "name": "swagger-stats-testapp",
  "version": "0.90.1",
  "hostname": "hostname",
  "ip": "127.0.0.1"
}

Take a look at Documentation for more details on API and returned statistics.

Get Prometheus Metrics

$ curl http://<your app host:port>/swagger-stats/metrics
# HELP api_all_request_total The total number of all API requests received
# TYPE api_all_request_total counter
api_all_request_total 88715
# HELP api_all_success_total The total number of all API requests with success response
# TYPE api_all_success_total counter
api_all_success_total 49051
# HELP api_all_errors_total The total number of all API requests with error response
# TYPE api_all_errors_total counter
api_all_errors_total 32152
# HELP api_all_client_error_total The total number of all API requests with client error response
# TYPE api_all_client_error_total counter
api_all_client_error_total 22986

. . . . . . . . . .  

Default Metrics

To collect prom-client default metrics:

const swaggerStats = require('swagger-stats');
const promClient = require('prom-client');

promClient.collectDefaultMetrics();

Some Node.js specific metrics are included, such as event loop lag:

# HELP nodejs_eventloop_lag_seconds Lag of event loop in seconds.
# TYPE nodejs_eventloop_lag_seconds gauge
nodejs_eventloop_lag_seconds 0.000193641 1597303877464

. . . . . . . . . .  

Updates

See Changelog

Enhancements and Bug Reports

If you find a bug, or have an enhancement in mind please post issues on GitHub.

License

MIT

swagger-stats's People

Contributors

dependabot[bot] avatar erajabzadeh avatar etiennea avatar gitphill avatar gombosg avatar hmshwt avatar ignaciocavina avatar intribvadell avatar justdoitsascha avatar lafittg avatar n0v1 avatar nas84 avatar ridakk avatar shimaore avatar shubhamp-sf avatar spijs avatar steven-sheehy avatar sv2 avatar vonoro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swagger-stats's Issues

Last Errors and Errors tab no populated using FeatherJS

swsAPIstats.js

Error thrown at line 513
this.promClientMetrics.api_response_size_bytes.labels(req.method,req.sws.api_path,res.statusCode).observe( req.sws.res_clength ? req.sws.res_clength : 0 );

if(req.sws.res_clength) = null. if response.c_length = 0;

Propagated from all the way from response intercept.

FIX
this.promClientMetrics.api_response_size_bytes.labels(req.method,req.sws.api_path,res.statusCode).observe( req.sws.res_clength ? req.sws.res_clength : 0 );

added a ternary operator to fix the issue.

Let me know if this is an actual bug, will submit a PR.

Add label "code" to Prometheus histogram metrics

Add label "code" with response code to Prometheus metrics:

Metric Type Labels Description
api_request_duration_milliseconds histogram method
path
le
API requests duration
api_request_size_bytes histogram method
path
le
API requests size
api_response_size_bytes histogram method
path
le
API response size

Update Grafana dashboard to calculate Apdex Score taking into account response code (code=~"^2..$") for satisfying and tolerated counts

nodejs cluster mode

If my app is running in cluster mode (via cluster module or PM2), every time I call the /metrics endpoint I'll get data from a different process, without the possibility to have the "general picture".
Am I missing something?

Thanks

Cannot upload to elk and Built-In API Telemetry

request example:

{
    
    "type": "pushQuestionnaire",
    "session_user_id": "153xxxx",
    "page_id": "62435xxxx",
    "email": "[email protected]",
    "skillId": "5a45998cxxx0",
    "access_token": "eyJhbGciOiJIUzI1Nixxxx",
    "prechat_survey": [
        "New question|",
        "How can we help you?|Versandinformationen (Vorverkauf)",
        "Email Address*|[email protected]",
        "What is your name?*|士大夫"
    ],
    "plat":{
    	"handler":"ac936992-2cc1-429c-bd4f-ad0d1846db55",
    	"msgid":"3629"
    }
}

Cannot upload to elk and Built-In API Telemetry

TypeError: Cannot read property 'handler' of undefined
swsInterface.js:99
message:"Cannot read property 'handler' of undefined"
stack:"TypeError: Cannot read property 'handler' of undefined\n    at Object.module.exports.swsStringRecursive (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsUtil.js:217:57)\n    at Object.module.exports.swsStringRecursive (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsUtil.js:217:32)\n    at swsProcessor.collectRequestResponseData (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsProcessor.js:264:17)\n    at swsProcessor.processResponse (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsProcessor.js:372:20)\n    at handleResponseFinished (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsInterface.js:97:19)\n    at ServerResponse.<anonymous> (F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsInterface.js:90:9)\n    at emitNone (events.js:111:20)\n    at ServerResponse.emit (events.js:208:7)\n    at onFinish (_http_outgoing.js:720:10)\n    at _combinedTickCallback (internal/process/next_tick.js:131:7)\n    at process._tickCallback (internal/process/next_tick.js:180:9)"
__proto__:Error {constructor: , name: "TypeError", message: "", …}

I found that a place needs to be changed to solve it.
F:\SVN\即时通讯\zc\share2.0\node_modules\swagger-stats\lib\swsUtil.js


// returns object key values as string recursively
module.exports.swsStringRecursive = function(output, val) {
    if (typeof val === "object" && !Array.isArray(val)) {
        for (var key in val) {
            // output[key] = this.swsStringRecursive(output[key], val[key]);
            // output[key] = this.swsStringRecursive(output[key] || val[key], val[key]);
            output[key] = JSON.stringify(val[key]);
        }
    } else {
        output = this.swsStringValue(val);
    }

    return output;
}

AWS Lambda support

Hey,
thanks for that great tool.

I used this library in combination with loopback framework (express) and aws lambda.
It works 👍 but I always get 502 errors for stylesheets and javascript files, when I invoke the /swagger-stats/ui page. Another thing is that it wont show the font-awesome icons. So its more of a styling issue rather than a functional issue.

In my local test environment this works without any issues.

So my question:
Anyone has a clue how to adjust the apigateway (and cloudfront) settings to pass these files trough without issues ?

Support Koa framework

app.js:
const app = require('koa')();
const api = require('koa-router')();
var swStats = require('swagger-stats');
app.use(swStats.getMiddleware({}));

log:
AssertionError: app.use() requires a generator function

Support custom attributes in Request Response Record stored in ElasticSearch

Pick additional data from both request and response, add it to Request Response Record and store in ElasticSearch. Allow application to add custom attributes to Request Response Record. This is to enable reporting in ElasticSearch / Kibana based on custom application-specific attributes.

Define flexible custom attributes in the schema by using dynamic mapping:

{
   "attributes": {
       "path_match": "attributes.*",
           "mapping": {
              "type": "keyword"
             }
         }
}

This should allow app to add anything under rrr.attributes and ES would index it correctly as long as values casted to strings.

Additional discussion are in #4, #27

use auth header better than cookie

My server doesn't use cookie. No config for cookie proxy, so it can't set cookie.
But authentication is important and there comes a problem that only the first request with header can be permitted.
I suggest all requests with basic auth header instead of using cookie.

Process does not finish when running jest tests

Hi everyone,
First of all, thanks for your help and support in monitoring API´s performance. I find it really useful.
I have an issue once the middleware swagger-stat is imported. When I run test with JEST, I have noticed that it does not come back to the shell, so the process does not finish successfully.
However, if I do not use the middleware, the process regarding the aforementioned test I am running, ends successfully.
Could you give any advice regarding this issue?

Integrating with existing express app

Guys,

A great APM tool. Getting it implemented in all of my new projects.
One thing I needed to ask how can I use it in my existing nodejs projects ? I have app written in express 4 and uses mysql as the DB. Any help would be highly appreciated.

Thanks

Support providing Prometheus metrics via prom-client library

Support providing Prometheus metrics via recommended node.js Prometheus Client library - prom-client.

Application would typically use recommended Prometheus client library to collect and expose all metrics. Swagger-stats must add its metrics to prom-client as a custom collector, and rely on prom-client to provide all metrics to Prometheus.

Only recognizing errors running locally

Hi, I'm really excited about integrating this into our project but I'm running into this issue when I run locally - swagger-stats will report bad endpoint calls but not successful ones.

Our project modifies the swagger object depending on the environment like so:

import originalSwaggerObject from './swagger.json'
import { devHost, npHost, prodHost } from '../config/params'

export default () => {
  let swaggerObject = {...originalSwaggerObject}
  if (process.env.NODE_ENV === 'local_dev') {
    swaggerObject.schemes = ['http']
    swaggerObject.host = 'localhost:3000'
    swaggerObject.basePath = '/myapi'
  }
  else {
    swaggerObject.basePath = '/myapi/v2'
    if (process.env.NODE_ENV === 'dev') {
      swaggerObject.host = devHost
    }
    else if (process.env.NODE_ENV === 'np') {
      swaggerObject.host = npHost
    } else {
      swaggerObject.host = prodHost
    }
  }
  return swaggerObject
}

In app.js:

import express from 'express'
...
import swStats from 'swagger-stats'
import SwaggerParser from 'swagger-parser'
import swaggerObj from './swagger/util'
...
const app = express()
...
let parser = new SwaggerParser()
parser.validate(swaggerObject, (err, api) => {
  if (!err) {
    logger.info('Succeeded in validating swagger file')
    app.use(swStats.getMiddleware({
      swaggerSpec: api,
      uriPath: swaggerObject.basePath,
      name: 'swagger-stats-test'
    }))
  } else {
    logger.error(err)
    logger.error('Failed to validate swagger file')
  }
})
...

Any ideas?

Save data to db? multi-node support?

So far I'm very impressed, thanks for all the hard work!

Correct me if I'm wrong, but I see 2 big issues with the project at the moment:

  1. Functionality is limited to 1 instance, there is no aggregated data. In modern applications 1 node is usually not enough.

  2. Data is saved in memory and therefore gets deleted upon application restart, saving data in a database (PostgreSQL; MySQL) will increase the usability of the product by a lot and will also allow issue no. 1 to be solved more easily.

Are these things being considered?

Prevent tracking of specific routes

Hello!

If I create a swagger doc to track specific URL, let's give an example I want to track

/iwanttotrack/certainIssue

But this URL falls under a routing system that does

/iwanttotrack/:issue

As of now, swagger-stats tracks both. Is there a way that I can prevent the tracking of the latter route and only track the specific URL that I want it to track?

Thanks!

Different data shown each time

Hi

I am using Kubernetes/PM2 with my express server - 2 processes running in PM2 cluster mode per pod & 2 replicas for k8s (so 4 processes in total I guess)

I see different data everytime I refresh the UI, is there a way to aggregate the traffic data into a single source?

DOS attack

It seems one could easily perform a DOS attack by:

  • sending REST request to an API path not specified in swagger
  • alter this path (or even just query parameters) with each request
  • perform this for about a week or so - scripted
  • patiently wait - memory consumption will grow until the service runs oom

I am afraid (at least in 0.94.1) it is caused by "swsProcessor.prototype.processResponse" in swsProcessor.js:
line 332: req.sws.api_path = (route_path!=''?route_path:req.originalUrl);
could result in bad experience

Q: Why not simply make req.sws.api_path an empty string in this scenario? Or even skip detailed statistics for such requests?
Or did I miss any configuration option to prevent this?

Cannot read property 'result' of undefined in Grafana

Hello,

Currently trying to hook up Swagger-Stats with Grafana to handle remote monitoring and alerts.
I've connected Grafana to /swagger-stats/metrics and am getting a successful response.

Despite this I'm getting 'Cannot read property 'result' of undefined'.
Upon digging I've found that there is not diffrent between the response of /swagger-stats/metrics
and /swagger-stats/metrics/api/v1/query_range?query=api_all_request_total&start=1519362432&end=1519363332&step=30

Is this responsible for the issue? and is there any way around this.

Swagger-Stats & NodeJS at latest versions. Running behind Nginx reverse proxy.

Response for /swagger-stats/metrics/api/v1/query_range?query=api_all_request_total&start=1519362432&end=1519363332&step=30
queryresp.txt

Can't start on node v7.10.1, Mac Os 10.12.6

Hi,

i'm trying to install swagger stats but i get this error when i start the app:

/src/node_modules/prom-client/lib/gauge.js:219
                        throw new TypeError(Value is not a valid number: ${util.format(value)});
                        ^

TypeError: Value is not a valid number: undefined
    at /src/node_modules/prom-client/lib/gauge.js:219:10
    at Gauge.set (/src/node_modules/prom-client/lib/gauge.js:85:31)
    at swsCoreStats.calculateSystemStats (/src/node_modules/swagger-stats/lib/swsCoreStats.js:151:65)
    at swsCoreStats.tick (/src/node_modules/swagger-stats/lib/swsCoreStats.js:121:10)
    at Timeout.swsProcessor.tick (/src/node_modules/swagger-stats/lib/swsProcessor.js:137:20)
    at Timeout.ontimeout [as _repeat] (timers.js:400:34)
    at Timeout.wrapper [as _onTimeout] (timers.js:425:11)
    at tryOnTimeout (timers.js:232:11)
    at Timer.listOnTimeout (timers.js:202:5)

This is the line #151 of swsCoreStats.js:
this.promClientMetrics.nodejs_process_memory_external_bytes.set(this.sys.external);

This is this.sys content:

  rss: 95752192,
  heapTotal: 75632640,
  heapUsed: 46559352,
  external: undefined,
  cpu: 26.9837199868224

And this is the result of process.memoryUsage():

{ rss: 95752192, heapTotal: 75632640, heapUsed: 46559352 }

The external property is missing.

Elasticsearch support

Store request/response record in ElasticSearch. Each request/response record to be individual document in the index. Index name to be time-based : sws-YYYY.MM.DD. Document structure and index template to be compatible with packetbeat http document, extending it with additional api-specific properties.

Change default UI path

Hello,

Will be nice, if is possible to change the default UI path from "/swagger-stats/ui" to "/mypathapi/stats/"
for example.

Why?

I have multiples Nodejs services running, and nginx are controlling the access, something like:
api.company.com/serviceOne -> 10.0.1:3000/serviceOne
api.company.com/serviceTwo -> 10.0.1:3001/serviceTwo
But when try api.company.com/swagger-stats, I can't have multiples Nodejs running, I have to choose
redirect just for one, like 10.0.1:3001/swagger-stats...
Any idea how to solve this? any tip?

Thanks again!

change elk index

I want to use different index!
well!
if change the


change to

 "template": "server-1-*",

ok?

or


app.use(swStats.getMiddleware({
    elasticsearch: "http://10.40.2.89:9200",
    elasticsearchIndex: "server-1-*"  // Configuration els index
}));

module.exports.supportedOptions = {

// swagger-stats supported options
module.exports.supportedOptions = {

    // ....
    // ElasticSearch URL. Enables storing of request response records in Elasticsearch.
    // Default is empty (disabled).
    elasticsearch: "elasticsearch",
    elasticsearchIndex: "api-*", // elk default index

   //...

};

swsElasticEmitter.prototype.initialize = function (swsOptions) {

// Initialize
swsElasticEmitter.prototype.initialize = function(swsOptions) {

    if (typeof swsOptions === 'undefined') return;
    if (!swsOptions) return;

    this.options = swsOptions;

    // Set or detect hostname
    if (!(swsUtil.supportedOptions.elasticsearch in swsOptions)) {
        debug('Elasticsearch is disabled');
        return;
    }
    if (this.options.elasticsearchIndex) {
        indexTemplate.template = this.options.elasticsearchIndex
    }

   //......

};

swsElasticEmitter.prototype.processRecord = function(rrr){

// Index Request Response Record
swsElasticEmitter.prototype.processRecord = function(rrr) {

    //...
    // Create metadata
    var indexName = this.options.elasticsearchIndex + moment(rrr['@timestamp']).utc().format('YYYY.MM.DD');
    var meta = { index: { _index: indexName, _type: this.options.elasticsearchIndex, _id: rrr.id } };
    // console.log(indexTemplate)
    // Add to buffer
    // .....
};

it is ok?

Authentication protection for swagger-stats?

Hello, first of all, really great job! Congrats !!I

I have two concerns about this.
The first one, is about memory leak, is that possible, because all the information is stored at runtime memory right?
What you can say about that.

The second one, is about how to protect the access to stats, is possible to add some authentication?

Thx!

Support custom metrics

Allow app to submit custom metrics. Provide Inc/Dec operations. Keep overall values, and time- interval values. Examples: number of DB connections, time to execute internal operations, number of items in queue, etc.

feature request: allow onAuthenticate to be asynchronous

Can you please allow onAuthenticate to be asynchronous? Looking login/pass up from a database is necessarily async, so allowing onAuthenticate to return a promise or accept a callback to call when the credentials are checked would be great.

Request Content Length null or undefined

https://github.com/slanatech/swagger-stats/blob/master/lib/swsAPIStats.js

this.promClientMetrics.api_response_size_bytes.labels(req.method,req.sws.api_path,res.statusCode).observe(req.sws.res_clength);

TypeError: Invalid value: is not number

bug - req.sws.res_clength

https://github.com/slanatech/swagger-stats/blob/master/lib/swsCoreStats.js

if ("_contentLength" in res){
    resContentLength = res['_contentLength'];
}else{
    // Try header
    if(res.hasHeader('content-length')) {
        resContentLength = res.getHeader('content-length');
    }
}

resContentLength - Null or Undefined

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.