Giter Site home page Giter Site logo

nitishm / go-rejson Goto Github PK

View Code? Open in Web Editor NEW
340.0 8.0 46.0 4.13 MB

Golang client for redislabs' ReJSON module with support for multilple redis clients (redigo, go-redis)

License: MIT License

Go 99.67% Shell 0.33%
golang redis-client redigo rejson redis go-redis multiclient json golang-client

go-rejson's Introduction

Note: Currently, go-ReJSON only support redislabs/rejson with version <=1.0.8. If you are using higher versions, some commands might not work as expected

Go-ReJSON - a golang client for ReJSON (a JSON data type for Redis)

Go-ReJSON is a Go client for ReJSON Redis Module.

Go Reference test code-analysis codecov Go Report Card GitHub release

ReJSON is a Redis module that implements ECMA-404 The JSON Data Interchange Standard as a native data type. It allows storing, updating and fetching JSON values from Redis keys (documents).

Primary features of ReJSON Module:

* Full support of the JSON standard
* JSONPath-like syntax for selecting element inside documents
* Documents are stored as binary data in a tree structure, allowing fast access to sub-elements
* Typed atomic operations for all JSON values types

Each and every feature of ReJSON Module is fully incorporated in the project.

Enjoy ReJSON with the type-safe Redis client, Go-Redis/Redis or use the print-like Redis-api client GoModule/Redigo. Go-ReJSON supports both the clients. Use any of the above two client you want, Go-ReJSON helps you out with all its features and functionalities in a more generic and standard way.

Support for mediocregopher/radix and other Redis clients is in our RoadMap. Any contributions to the support for other clients is hearty welcome.

Installation

go get github.com/nitishm/go-rejson/v4

Example usage

package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"

	"github.com/nitishm/go-rejson/v4"
	goredis "github.com/go-redis/redis/v8"
	"github.com/gomodule/redigo/redis"
)

// Name - student name
type Name struct {
	First  string `json:"first,omitempty"`
	Middle string `json:"middle,omitempty"`
	Last   string `json:"last,omitempty"`
}

// Student - student object
type Student struct {
	Name Name `json:"name,omitempty"`
	Rank int  `json:"rank,omitempty"`
}

func Example_JSONSet(rh *rejson.Handler) {

	student := Student{
		Name: Name{
			"Mark",
			"S",
			"Pronto",
		},
		Rank: 1,
	}
	res, err := rh.JSONSet("student", ".", student)
	if err != nil {
		log.Fatalf("Failed to JSONSet")
		return
	}

	if res.(string) == "OK" {
		fmt.Printf("Success: %s\n", res)
	} else {
		fmt.Println("Failed to Set: ")
	}

	studentJSON, err := redis.Bytes(rh.JSONGet("student", "."))
	if err != nil {
		log.Fatalf("Failed to JSONGet")
		return
	}

	readStudent := Student{}
	err = json.Unmarshal(studentJSON, &readStudent)
	if err != nil {
		log.Fatalf("Failed to JSON Unmarshal")
		return
	}

	fmt.Printf("Student read from redis : %#v\n", readStudent)
}

func main() {
	var addr = flag.String("Server", "localhost:6379", "Redis server address")

	rh := rejson.NewReJSONHandler()
	flag.Parse()

	// Redigo Client
	conn, err := redis.Dial("tcp", *addr)
	if err != nil {
		log.Fatalf("Failed to connect to redis-server @ %s", *addr)
	}
	defer func() {
		_, err = conn.Do("FLUSHALL")
		err = conn.Close()
		if err != nil {
			log.Fatalf("Failed to communicate to redis-server @ %v", err)
		}
	}()
	rh.SetRedigoClient(conn)
	fmt.Println("Executing Example_JSONSET for Redigo Client")
	Example_JSONSet(rh)

	// GoRedis Client
	cli := goredis.NewClient(&goredis.Options{Addr: *addr})
	defer func() {
		if err := cli.FlushAll(context.Background()).Err(); err != nil {
			log.Fatalf("goredis - failed to flush: %v", err)
		}
		if err := cli.Close(); err != nil {
			log.Fatalf("goredis - failed to communicate to redis-server: %v", err)
		}
	}()
	rh.SetGoRedisClient(cli)
	fmt.Println("\nExecuting Example_JSONSET for GoRedis Client")
	Example_JSONSet(rh)
}

go-rejson's People

Contributors

breno12321 avatar cyberbeast avatar dc-dc-dc avatar hkairi avatar mvasilenko avatar nitishm avatar prabeshmagar avatar shivam010 avatar tinuschen avatar u5surf avatar vedhavyas avatar yafimk 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

go-rejson's Issues

When I read a special character, it appears a garbled code

Describe the bug
When I read a special character, it appears a garbled code.I found that this is due to an overflow when converting a string to byte.

rjs/helper.go line:17

// StringToBytes converts each character of the string slice into byte, else panic out
func StringToBytes(lst interface{}) (by []byte) {
	_lst, ok := lst.(string)
	if !ok {
		panic("error: something went wrong")
	}
	for _, s := range _lst {
		by = append(by, byte(s))
	}
	return
}

Bug recurrence:

func main()  {
	_lst := "test🌸test"
	fmt.Println(string(StringToBytes(_lst)))
}

// StringToBytes converts each character of the string slice into byte, else panic out
func StringToBytes(lst interface{}) (by []byte) {
	_lst, ok := lst.(string)
	if !ok {
		panic("error: something went wrong")
	}
	for _, s := range _lst {
		by = append(by, byte(s))
	}
	return
}

Run the above code and you will get:

test8test

If adjusted in this way, you will get a correct result:

func main()  {
	_lst := "test🌸test"
	fmt.Println(string(StringToBytes(_lst)))
}

// StringToBytes converts each character of the string slice into byte, else panic out
func StringToBytes(lst interface{}) (by []byte) {
	_lst, ok := lst.(string)
	if !ok {
		panic("error: something went wrong")
	}
	return []byte(_lst)
}

Trying to JSONSet path object, works in redis-cli but not in go-rejson

Describe the bug
I'm trying to call an object which is in my json as I can call it using the JSON path in the redis-cli
.Object'["id"]["subObj"]'
But when I try to JSONSet or JSONGet in my code using the same path I receive the following error: "ERR Search path error at offset 14: an identifier can only contain letters, digits, dollar signs or underscores - use bracket notation for anything else"

Any tips to how I can fix this?

To Reproduce
Steps to reproduce the behavior:
response, err := handler.JSONSet(id, ".Object'["+strconv.Quote(userId)+"]["+strconv.Quote("subObj")+"]'", obj)
if err != nil {
log.Printf("Error %v ", err)
}

Expected behavior
An "OK" response and the object being set to redis

Desktop (please complete the following information):

  • OS: MacOS

go-redis/v9 compatibility

I noticed you used go-redis/v9 in your examples and hoped to do the same.
When calling: jsonh.SetGoRedisClientWithContext(context.Background(), client)

I get the following error:
cannot use client (variable of type *"github.com/redis/go-redis/v9".Client) as clients.GoRedisClientConn value in argument to jsonh.SetGoRedisClientWithContext: *"github.com/redis/go-redis/v9".Client does not implement clients.GoRedisClientConn (wrong type for method Do). have Do(context.Context, ...interface{}) *"github.com/redis/go-redis/v9".Cmd. want Do(context.Context, ...interface{}) *"github.com/go-redis/redis/v8".Cmd

Also, in my go.mod file after running go mod tidy
I got the v8 installed as an indirect dependency

Here's my Redis Client setup:

jsonh := rejson.NewReJSONHandler()

rdb.setConnectUri()
opt, err := redis.ParseURL(rdb.connectUri)

client := redis.NewClient(opt)
jsonh.SetGoRedisClientWithContext(context.Background(), client)

So curious as to why this works in your examples, but I'm unable to do the same.

Thanks,
Ron

Mocking ReJSON in a mock redis server

Is there any way to mock rejson in a mocked Redis server in golang?

I am able to mock a Redis server using something like this using miniredis and redismock

func newTestRedis() (*redismock.ClientMock, *redis.Client) {
	mr, err := miniredis.Run()
	if err != nil {
		panic(err)
	}
	client := redis.NewClient(&redis.Options{
		Addr: mr.Addr(),
	})
	return redismock.NewNiceMock(client.Client), client
}

It is able to do normal Redis operations like Get, Set but since I am using ReJSON module, I am not able to run any ReJSON commands on that.

Thanks

`redis: client is closed` only with go-redis/v8 + go-rejson/v4

Describe the bug
I get an error trying to access redis either via go-redis or go-rejoin, once I add go-rejson to my code.

To Reproduce
Basically close to the default example. Accessing either the database via either redis.Client or rejson.Handler will cause the redis: client is closed error. Removing rejson.Handler from my setup to look like the second code block fixes my issue (which is not ideal, since I'd like to use go-rejson).

// Causes database to just not be accessible
func SetupDatabase() (*redis.Client, *rejson.Handler) {
	rh := rejson.NewReJSONHandler()

	client := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: redisPass,
	})
	defer func() {
		if err := client.FlushAll(ctx).Err(); err != nil {
			log.Fatalf("goredis - failed to flush: %v", err)
		} else {
			log.Printf("goredis - flushed")
		}
		if err := client.Close(); err != nil {
			log.Fatalf("goredis - failed to communicate to redis-server: %v", err)
		}
	}()

	rh.SetGoRedisClient(client)
	return client, rh
}
// Works fine
func SetupDatabase() (*redis.Client, *rejson.Handler) {
	client := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: redisPass,
	})
	return client
}

Expected behavior
It works fine

Desktop (please complete the following information):

  • OS: Arch
  • Redis: go-rejson v4
  • Redis server: v6.2.5

Additional context
It looks like client.PoolStats().Misses is 1 after doing the .FulshAll. Removing the .FlushAll does not fix anything, but it does change Misses to 0. client.PoolStats().TotalConns is always 0 for whatever reason.

I'm running redis-server 6.2.5.

Call a command inside a transaction/pipe

Is there a way to use a rejson command inside a transaction or pipe?
Something like that:

tx := redisClient.TXPipeline()
tx.XAdd(&redis.XAddArgs{Stream: stream.Name, ID: "*", Values: map[string]interface{}{"msg": "New stream"}})
tx.JSONSet(streamInfoKey(stream.Name), ".", stream)
tx.Exec()

Remove megacheck from travis CI and replace with staticcheck.

Megacheck is causing Travis CI to crash and fail.

$ megacheck .
Megacheck has been deprecated. Please use staticcheck instead.
panic: internal error: malformed position "/tmp/gopackages819637706/go-build/net/cgo_linux.cgo1.go:1"
goroutine 1 [running]:
honnef.co/go/tools/lint/lintutil.parsePos(0xc4261a7100, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:320 +0x331
honnef.co/go/tools/lint/lintutil.compileErrors(0xc420440fc0, 0x0, 0x0, 0x0)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:347 +0x134
honnef.co/go/tools/lint/lintutil.compileErrors(0xc4202cf5e0, 0x0, 0x0, 0x0)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:340 +0x456
honnef.co/go/tools/lint/lintutil.compileErrors(0xc4202cba40, 0xc420409bc0, 0xc4200e3350, 0x7f9eb46746c8)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:340 +0x456
honnef.co/go/tools/lint/lintutil.compileErrors(0xc4202ecb60, 0xc420409b90, 0xc4200e3540, 0x0)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:340 +0x456
honnef.co/go/tools/lint/lintutil.compileErrors(0xc4201da2a0, 0x0, 0x3, 0xc4264e5da0)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:340 +0x456
honnef.co/go/tools/lint/lintutil.Lint(0xc420089280, 0x3, 0x4, 0xc42008a010, 0x1, 0x1, 0xc4200e3d90, 0x900220, 0xc42007ea28, 0x0, ...)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:287 +0x4d7
honnef.co/go/tools/lint/lintutil.ProcessFlagSet(0xc420089280, 0x3, 0x4, 0xc4200a6660)
	/home/travis/gopath/src/honnef.co/go/tools/lint/lintutil/util.go:178 +0x9b8
main.main()
	/home/travis/gopath/src/honnef.co/go/tools/cmd/megacheck/megacheck.go:109 +0x7e6
The command "megacheck ." exited with 2.

The message shows megacheck has been deprecated and is to be replaced with staticcheck.

Approach this in two phases -

  1. Remove megacheck
  2. Introduce staticcheck (or any other alternative)

Using JSON.SET with expiry

Is your feature request related to a problem? Please describe.

As described here RedisJSON/RedisJSON#56. I want to set a json key with some expiry. However, I understand it is not supported by ReJSON directly how could I use go-rejson to solve this? Is this supported ? If not I would be willing to help out. Any pointers would be helpful.

Describe the solution you'd like
A command like JSONSetWithExpiry to set expiry for a JSON Key.

Describe alternatives you've considered
I guess I could accomplish this using the underlying redis client but since I will be using your library, a method like JSONSetWithExpiry would be a nice abstraction.

Example `json_obj.go` failing to execute

Example code is failing with error -

➜  go-rejson git:(master) ✗ go run examples/json_obj.go
# command-line-arguments
examples/json_obj.go:82:4: undefined: rejson.JSONGetOptionIndent
examples/json_obj.go:82:39: undefined: rejson.JSONGetOptionNewLine
examples/json_obj.go:83:4: undefined: rejson.JSONGetOptionSpace
examples/json_obj.go:83:37: undefined: rejson.JSONGetOptionNoEscape

Code snippet -

json_obj.go
------------
...
	res, err = rejson.JSONGet(conn, "obj", ".",
		&rejson.JSONGetOptionIndent{"\t"}, &rejson.JSONGetOptionNewLine{"\n"},
		&rejson.JSONGetOptionSpace{" "}, &rejson.JSONGetOptionNoEscape{})
	if err != nil {
		log.Fatalf("Failed to JSONGet")
		return
	}
...

structs JSONGetOptionIndent do not exist in rejson.go and have been converted to constructors NewJSONGetOptionIndent.

Convert this code to use the ctors to make it pass.

Set Go Redis V7 Client Problem

HI, I want so set the goredis/v7 to use rejson, but when I set the client,

the error shows:

Cannot use (type *"github.com/go-redis/redis/v7".Client) as type *"github.com/go-redis/redis".Client 

looks like the lib only accept "github.com/go-redis/redis" (v6),

can fix the problem? thanks..

Update README documentation with SetGoRedisClient

Is your feature request related to a problem? Please describe.
The method SetGoRedisClient is deprecated, but being used as example in the README doc

Describe the solution you'd like
Docs updates to the correct way for GoRedis client connection

jsonGet return multiple paths (fields) for a given key

Not entirely sure if this is a feature request, or my ignorance?

In the native redis-cli this command works:
JSON.GET somekey path1 path2 path3
In rejson this command works:
jsonGet(somekey, "path1")
However, this command doesn't:
jsonGet(somekey, "path1 path2 path3")

Am I missing something about how to return multiple paths (fields) from jsonGet?
Should I be using the options in the function signature?

... or possibly change the function signature?
from:
JSONGet(key, path string, opts ...rjs.GetOption) (res interface{}, err error)
to:
JSONGet(key, path []string, opts ...rjs.GetOption) (res interface{}, err error)

Create a JSONQGet function

RedisJSON2 was released, and with it has the funcionality of make GET with Queries, which is called JSON.QGET. So, I wanted to do the same in Go, and it didn't was avaiable yet.

With this in mind, I created the command to execute de JSON.QGET with go-rejson, and I'd like to know what could I do to improve the code, and if we could do a PR, for others who need use it.

Or if there is another way to do it and I didn't find, please tell me.

Its forked on my repo

Deleting key crashes the re-json server

**Deleting key crashes the rejson server **
Trying to delete redis key using res, err :=rejson.JSONDel(conn, sessionId, "") It crashes the rejson server. For rejson server i am using
docker run -p 6379:6379 --name redis-rejson redislabs/rejson:latest

To Reproduce
Steps to reproduce the behavior:

  1. Go to
func DeleteSessionInfo(sessionId string) (interface{}, error) {
	conn := Pool.Get()
	defer conn.Close() 
	res, err :=rejson.JSONDel(conn, sessionId, "")
	if err != nil {
		Logger.Errorf("Redis: Retrieve session info failed:  %s", err.Error())
               //returns the  --> Redis: Retrieve session info failed:  EOF
		return res, err
	} 
	return res, nil
}
  1. Check docker screen on terminal it throws the error given below.

Expected behavior
It should delete the requested key instead of crashing rejson server.

Screenshots
screenshot1
screenshot4
screenshot3
screenshot2

Desktop (please complete the following information):

  • OS: Ubuntu

rejson server stack trace

------ DUMPING CODE AROUND EIP ------
Symbol: JSONDel_RedisCommand (base: 0x7f9ea63eadc0)
Module: /usr/lib/redis/modules/rejson.so (base 0x7f9ea63e2000)
$ xxd -r -p /tmp/dump.hex /tmp/dump.bin
$ objdump --adjust-vma=0x7f9ea63eadc0 -D -b binary -m i386:x86-64 /tmp/dump.bin

1:M 14 Sep 09:50:40.385 # dump of function (hexdump of 552 bytes):
41568d42fe415541545589d5534889fb4883ec1083f8017627488b052015210041bc01000000ff104883c4104489e05b5d415c415d415ec30f1f840000000000488b05b11521004989f4ff10488b05cd142100498b742408ba030000004889dfff104889c74989c5488b0549142100ff1085c07443488b05d41521004c89efff10483b05b01921007456488b054f1521004889df41bc01000000488d35dfbb0000ff104883c4104489e05b5d415c415d415ec30f1f440000488b05991321004889df4531e431f6ff104883c4104489e05b5d415c415d415ec30f1f8000000000488b05011521004c89efff1083fd034989c648c7442408000000007553498b742410498b3e488d542408e821deffff85c04189c4488b7424080f85c90000008b46488d50ff83fa010f86c700000085c0743e4889dfe8f6e6ffff488b7c240841bc01000000e8b6ddffffe9d9feffff90488b0569152100488d3586b10000ba010000004889dfff104889c6eb950f1f004c89f7e8d8d9ffff488b5424088b4228488b4a2083f801747c488b7a184885ff740a837f10200f84bd00000083e801ba0100000048c1e0048b740108e8bf36000085c07568488b059c1221004863f54889df4883ee02ff10488b7c2408e82eddffff488b054f1221004889dfff10e945feffff0f1f4400004889dfe850deffffe945ffffff488b055c12210031f64889dfff10ebc38b3185f60f857affffff488b05ea1321004c89efff10eb984c8b059c1321004889df31
Function at 0x7f9ea63e8cf0 is NodeFromJSONPath
Function at 0x7f9ea63e95f0 is ReplyWithPathError
Function at 0x7f9ea63e8cc0 is JSONPathNode_Free
Function at 0x7f9ea63ee630 is Node_ArrayDelRange
Function at 0x7f9ea63e8e00 is ReplyWithSearchPathError

=== REDIS BUG REPORT END. Make sure to include from START to END. ===

   Please report the crash by opening an issue on github:

       http://github.com/antirez/redis/issues

Suspect RAM error? Use redis-server --test-memory to verify it.

Can't get the library using latest otel and go-redis v9

Describe the bug
Hello! When trying to go get github.com/nitishm/go-rejson/v4 I get such error: go.opentelemetry.io/otel/label: cannot find module providing package go.opentelemetry.io/otel/label. Seems to be related to: redis/go-redis#1678 . Could you please upgrade otel and change usage of label to attributes?

To Reproduce
Steps to reproduce the behavior:

  1. Use otel v1.14.0
  2. Try to get this lib
  3. See error

Expected behavior
The lib should install properly.

Support go-redis as the redis client

The goal of this feature is to add support for more redis clients like go-rejson, gosexy/redis,etc., rather than have it tightly coupled with redigo, which is how it is currently written to work.

The go-rejson library relies on the redigo.Conn object, which is passed in as a dependencies to each of the exported methods, which in turn rely on the Do() method of the redigo.Conn object.

See JSONSet - https://github.com/nitishm/go-rejson/blob/master/rejson.go#L273-L279

The feature/enhancement should keep the library backwards compatible (if possible) by abstracting away the conn.Do() method, in a way that it works with all supported client libraries.

add support for go-redis v9(redis v7.0)

I use redis v7 and go-redis v9,while go-rejson use go-redis v8,their apis have some difference,i cant pass go-redis v9's *redis.Client
to SetGoRedisClient function

Set Go Redis V8 Client Problem

Hi,

I wanted to report incompatibilities with v8 of go-redis. According to go-redis documentation, v8 is the latest recommended version.

Very similar to the issue concerning upgrading from go-redis v6 to v7.

Remove direct dependency of clients for obtaining connection

go-redis provides 4 different types of protocols to connect to Redis

Similarly, Redigo provides a single method:

And as we only use Do method of both the clients. Hence, in order to support these different types of connections in each client, abstracting the required method is the only feasible option

Originally posted by @Shivam010 in #62 (comment)

Invalid data is read in JSONGet when a struct with Unicode strings is passed into JSONSet.

Describe the bug
JSONGet does not produce the correct output for Cyrillic text.

To Reproduce
Steps to reproduce the behavior:

  1. Use JSONSet to write a structure with string fields. Fill the fields with Unicode characters.
  2. Use res, err := JSONGet() to read the structure.
  3. Convert res into []byte either manually (res.[]byte), or using redigo.Bytes(res).
  4. Unmarshall the []byte result via json.Unmarshall() into the structure.
  5. Compare values you have written with values json.Unmarshal produced from JSONGet result.
  6. New structure will contain fields with different (seemingly random) characters.

Expected behavior
Fields in first structure (which we have written) and the second one (which was read) should match.

Additional context
The problem I found lies within rjs.StringToBytes function, which is called from JSONGet. There are the following lines (_lst is a string, by is []byte) :

for _, s := range _lst {
    by = append(by, byte(s))
}

Here, s is a rune, which is an alias for int32. When we convert it into byte, we loose all but the least significant byte. Fix is pretty straightforward, we just need to convert string into []byte directly, without looping over each rune:

by = []byte(_lst)

I've copied JSONGet in my own code and applied this fix, and my Unicode problem was solved.

Mocking JSONSet

Hi - I'm using redismock for unit testing. I am not able to get the JSONSet mocked. Tried ExpectHMSet, ExpectSet etc. but no dice. Has anyone done this?

Installation step does not work

Describe the bug
go get github.com/nitishm/go-rejson throws the following error

"package github.com/go-redis/redis/v7: cannot find package "github.com/go-redis/redis/v7" in any of"

To Reproduce
go get github.com/nitishm/go-rejson

Expected behavior
Package should install properly

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):
macOS 10.15.5

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.