Giter Club home page Giter Club logo

rest-client-sdk's People

Contributors

ambroisemaupate avatar badaz avatar bjulien avatar dallegoet avatar dependabot[bot] avatar didier2l avatar fe4nn0r avatar jdeniau avatar jmfeurprier avatar julienravia avatar leroy0211 avatar nickinthebox avatar scrutinizer-auto-fixer avatar steit avatar thomasdiluccio avatar

Stargazers

 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

rest-client-sdk's Issues

retrieving a list of "abstracted" entities

Hi there,

We have an entity hierarchy as such (simplified) :

  • abstract Document { id, title, author }
  • Article extends Document { content }
  • Recipe extends Document { ingredients, calories }

We have an API end-point for documents which allows to make queries based on shared properties (id, title, author) from the Document base class. Here is a sample response for GET /documents :

{
  "@context": "/contexts/Document",
  "@id": "/documents",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/articles/320d346d-0c8f-11e7-8f02-0242ac150002",
      "@type": "Article",
      "id": "320d346d-0c8f-11e7-8f02-0242ac150002",
      "title": "I am an article",
      "author": "Me",
      "content": "article content"
    },
    {
      "@id": "/recipes/320d45f8-0c8f-11e7-8f02-0242ac150002",
      "@type": "Recipe",
      "id": "320d45f8-0c8f-11e7-8f02-0242ac150002",
      "title": "I am a recipe",
      "author": "You",
      "ingredients": "food and stuff",
      "calories": 5000
    }
  ],
  "hydra:totalItems": 2,
  "hydra:search": {
    // ...
  }
}

And then, when we try to call this end-point with the SDK client, the model hydrator explodes:

Cannot instantiate abstract class AppBundle\Entity\Document

Stack Trace
    in vendor/mapado/rest-client-sdk/src/Model/Serializer.php at line 84  -
                $identifierAttribute = $classMetadata->getIdentifierAttribute();
                $identifierAttrKey = $identifierAttribute ? $identifierAttribute->getSerializedKey() : null;
                $instance = new $className();
                foreach ($data as $key => $value) {
                    $attribute = $classMetadata->getAttribute($key);
                }

Of course, the Document is not to be instantiated as it is abstract. The model hydrator receives the "entityName" from an entity repository (DocumentRepository in our case), and then asks to hydrate the list of entities with this entityName, but in fact it should use the "@type" of the collection items to instantiate each entity, and maybe just use the entity name to validate the instantiated entities?

What do you think, is there a way to make it work?

Creating relation entities even when they aren't resources

When the serializer deserialize the entity with:
$agente = $this->get('mapado.rest_client_sdk.agentes')->getRepository('agentes')->find(20);
if that entity, in this case "Agentes", have a relation with other entity but that entity doesn't have an iri identifier the app throws an exception like this:
image
That error means that the entity is handled like an resourse but it isn't.
But maybe something like other annotation or maybe an if condition on the desiarialization can make that a non resourse entity relation be handled as a rest relation.

i made something like that with the controller scope:

$serializer = $this->get('mapado.rest_client_sdk.agentes')->getSerializer();

$agente = $this->get('mapado.rest_client_sdk.agentes')->getRepository('agentes')->find(20);

$agente->setTipoCuil($serializer->deserialize($agente->getTipoCuil(), 'App\Entity\TipoCuil'));

This only works if you put the rest\entity annotation on the relation entity:

/**
 * TipoCuil
 * @Rest\Entity(key="tipoCuil")
 */
class TipoCuil`

and in Agentes:

`/**
 * @var array
 *
 * @Rest\Attribute(name="tipoCuil", type="array")
 */
 private $tipoCuil;

this would make all relationships be objects and no array like now when the relation is an nono iri relation.

sorry for my bad english and for the latest issues. This is a really good and useful project and i want to help with everything ahah

@Attribute name annotation giving NULL when the class parameter name is different

First of all let me define my resouces.

I use this Hydra API: http://www.markus-lanthaler.com/hydra/event-api/events/41
I created a class Event like:

/**
 * Class Event
 *
 * @package Acme\DemoBundle\Entity
 * @Rest\Entity(key="events", client="Acme\DemoBundle\Command\BasicClient")
 */
class Event
{
    /**
     * @var int
     * @Rest\Id()
     */
    protected $id;

    /**
     * @var string
     * @Rest\Attribute(name="name", type="string")
     */
    protected $firstName;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getFirstName()
    {
        return $this->firstName;
    }

    /**
     * @param string $firstName
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;
    }

}

Now when I try to get the Event Entity the Id is correct. But the $firstName attribute gives me back NULL.

When I change the $firstName attribute to $name, everything works like a charm.

It looks like the @Attribute name annotation doesn't seem to work as it should.

Handle exceptions from API

Hello,

I have a problem handling 400 response from API.

My problem is that I need to show a particular message when an admin tries to create a new user with an already used email.

The API returns this when it happens:

Response status code: 400
Response body: - Toggle response

{
    "@context": "\/contexts\/ConstraintViolationList",
    "@type": "ConstraintViolationList",
    "hydra:title": "An error occurred",
    "hydra:description": "email: This value is already used.",
    "violations": [
        {
            "propertyPath": "email",
            "message": "This value is already used."
        }
    ]
}

In my controller however, if I Try/Catch the call to the repository, I only have access to the ClientException (thrown in Mapado\RestClientSdk\RestClient::post), so I can't distinguish the particular "dupplicate email" error from other ones, even if the API sent the information in it's 400 response.

Please help, Merci beaucoup

DateTime : changing timezone

This follows #95, it could be usefull to change datetime timezone before formating.

This operation should not alter original value, so we need to convert DateTime instances to DateTimeImmutable (with DateTimeImmutable::fromMutable($d)) to do the job.

paginated hydra collections support

Not sure if this is an issue on the SDK side or the API side.

I'm querying an API endpoint which should return a collection of items (CGET), with a page (1) and a number of items per page (10), and I would expect to access the real total item count (5000), to build a pagination system. This information seem to be available through the HydraPaginatedCollection class and getTotalItems() method, but I always get a HydraCollection object, which only shows the number of returned items (10).

I'm making an API call with these parameters:

GET domain.tld/items?foo=bar&order[name]=ASC&itemsPerPage=10&page=1

And here is a sample of the response :

{
    "@context": "\/contexts\/Item",
    "@id": "\/items",
    "@type": "hydra:Collection",
    "hydra:member": [
        {
            "@id": "\/items\/bd87b2df-000b-11e7-a37a-0242ac150003",
            "@type": "Item",
            "id": "bd87b2df-000b-11e7-a37a-0242ac150003",
            "name": "foo"
        },
( more items here )
    ],
    "hydra:totalItems": 5000,
    "hydra:view": {
        "@id": "\/items?foo=bar&order%5Bname%5D=ASC&itemsPerPage=10&page=1",
        "@type": "hydra:PartialCollectionView",
        "hydra:first": "\/items?foo=bar&order%5Bname%5D=ASC&itemsPerPage=10&page=1",
        "hydra:last": "\/items?foo=bar&order%5Bname%5D=ASC&itemsPerPage=10&page=500",
        "hydra:next": "\/items?foo=bar&order%5Bname%5D=ASC&itemsPerPage=10&page=2"
    },
    "hydra:search": {
        ( ... irrelevant stuff here ... )
    }
}

The ModelHydrator::deserializeAll() method seems to rely on the value of the @type node to build a HydraPaginatedCollection instead of a HydraCollection :

        $hydratedList = new HydraCollection($data);

        if (!empty($data['@type'])) {
            if ($data['@type'] === 'hydra:PagedCollection') {
                $hydratedList = new HydraPaginatedCollection($data);
            }
        }

        return $hydratedList;

But in my response, the value of @type is 'hydra:Collection'.

Do you think the condition is too strict, or the API response too "loose" ? (API is driven by api-platform).

Do not allow two `@Rest\Id` fields

We do accept that two fields contains @Rest\Id, we should throw an error on that as the id is the url we will call for update / delete and only one is possible

Allow an ID instead of an IRI

Today, the ID needs to be an IRI with the full path.

It works fine with JSON-LD API but does not on other cases.

See #46 for more details

Using the SDK without a prefix

Hi,

we are using the SDK (with the Symfony bundle) with a REST API which has no URL prefix, ie, we have end-points like these:

http://domain.tld/articles
http://domain.tld/articles/434856bf-e37e-11e6-b8b0-0242ac110002

In the YML configs, we put these values:

            server_url: 'http://domain.tld'
            mappings:
                prefix: ~
                dir: '%kernel.root_dir%/../src/AppBundle/Entity/'

On our entities:

/**
 * @Rest\Entity(key="articles")
 */
class Article
{
[...]
}

But calls made by the SDK look like this (notice the missing slash /):
http://domain.tldarticles/434856bf-e37e-11e6-b8b0-0242ac110002

We then changed the YML property "prefix" from NULL (~) to '/' but then we get this:
http://domain.tld//articles/434856bf-e37e-11e6-b8b0-0242ac110002

We sort of hacked by putting 'http://domain.tld//' (2 slashes) in the server_url and a NULL prefix, but we get many other problems after (entities are converted to identifiers as "articles/...." instead of "/articles/...." for example).

Is the absence of URL prefix supported? If so, how should we configure the SDK?

Thanks in advance.

Split the Client in a Client and an Entity Repository

Wouldn't it be nicer to have a default Client which handles the Conversion and persisting, and a separate class like the Doctrine EntityRepository to handle lookups?

If we want to load a specific filter, we can create an EntityRepository and add the specific methods to load something specific. Next add the EntityRepository to the Entity.

If we would want to persist or convert in a different way, we extend the Client and add it to the Entity tell the sdkClient to use a different client

Relation serialization bug

When we try to update entity with relationships, sdk does not serialize relationships properly. In this example walletList is serialized as an array of strings (proper way) although minisiteList is serialized as an array of Minisite objects (thus not serialized?).

In this example, the contract we get has ids for wallets, and json objects for minisites, but if we get ids for minisites too the problem remains the same.

/**
 * Contract Model
 *
 * @Rest\Entity(key="contracts", repository="Mapado\Component\Ticketing\Model\Repository\ContractRepository")
 */
class Contract extends HasShortId
{
    /**
     * @var integer
     * @Rest\Attribute(name="id", type="string")
     * @Groups({"ticketing"})
     */
    private $id;

    /**
     * walletList
     *
     * @var array
     * @access private
     *
     * @Rest\OneToMany(name="walletList", targetEntity="Wallet")
     * @Groups({"wallet"})
     */
    private $walletList;

    /**
     * minisiteList
     *
     * @var array
     * @access private
     *
     * @Rest\OneToMany(name="minisiteList", targetEntity="Minsite")
     */
    private $minisiteList;
}
/**
 * Minisite Model
 *
 * @Rest\Entity(key="minisites", repository="Mapado\Component\Ticketing\Model\Repository\MinisiteRepository")
 */
class Minisite extends HasShortId
{
    /**
     * id
     *
     * @Rest\Id
     * @Rest\Attribute(name="id", type="string")
     * @Groups({"contract", "ticketing"})
     *
     * @var string
     * @access private
     */
    private $id;

    /**
     * contract
     *
     * @var Contract
     * @access private
     *
     * @Rest\ManyToOne(name="contract", targetEntity="Contract")
     * @Groups({"ticketing"})
     */
    private $contract;
}
/**
 * Wallet Model
 *
 * @Rest\Entity(key="wallets")
 *
 */
class Wallet extends HasShortId
{
    /**
     * @var integer
     *
     * @Rest\Id
     * @Rest\Attribute(name="id", type="string")
     */
    private $id;

    /**
     * contract
     *
     * @var Contract
     * @access private
     *
     * @Rest\ManyToOne(name="contract", targetEntity="Contract")
     * @Groups({"wallet"})
     */
    private $contract;
}

GET http://mon-ticketing-de-dev.com:81/v1/contracts/197
=>

{
  "@context": "/v1/contexts/Contract",
  "@id": "/v1/contracts/197",
  "walletList": [
    "/v1/wallets/165"
  ],
  "minisiteList": [
    {
      "@id": "/v1/minisites/183",
      "@type": "Minisite",
      "slug": "toto",
      "contract": "/v1/contracts/197",
    }
  ],
}

improve performance of related entities retrieval

Hi,

we encounter performance issues with related entities.

Given we make this API call:

GET https://api/articles/12345678-4792-11e7-88db-f23c9124c2b0

Which returns :

{
    "@context": "\/contexts\/Article",
    "@id": "\/articles\/12345678-4792-11e7-88db-f23c9124c2b0",
    "@type": "Article",
    "id": "12345678-4792-11e7-88db-f23c9124c2b0",
    "title": "foo bar",
    "tags": [
        "\/tags\/331a2c47-164a-11e7-8a8a-f23c9124c2b0",
        "\/tags\/331a658c-164a-11e7-8a8a-f23c9124c2b0",
        "\/tags\/331a71cc-164a-11e7-8a8a-f23c9124c2b0",
        "\/tags\/9c828580-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9c82e2b1-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9c834c02-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9c850c8b-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9c86ca17-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9cc9f244-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9cd4d60e-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d186137-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d194643-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d1f1245-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d1fe224-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d33f4f4-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d37d44d-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d4353fe-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9d5d71fd-75f3-11e7-8820-f23c9124c2b0",
        "\/tags\/9da0e8d6-75f3-11e7-8820-f23c9124c2b0"
    ]
}

When we iterate over the entity tags collection ($article->getTags()), each iteration makes an API call to retrieve the tag entity:

GET https://api/tags/331a2c47-164a-11e7-8a8a-f23c9124c2b0
GET https://api/tags/331a658c-164a-11e7-8a8a-f23c9124c2b0
GET https://api/tags/331a71cc-164a-11e7-8a8a-f23c9124c2b0
GET https://api/tags/9c828580-164a-11e7-8a8a-f23c9124c2b0
...

Which kills the performances of our application.

Embedding the tags in the article API response is not an option in our case (for a lot of reasons).

So my question is: is there a way to tell the API client to retrieve all the tags at once instead of retrieving them one by one ?

Symfony 3.0

Hi, I would like to know if you plan to make a version of rest-client-sdk compatible with Symfony 3.0.

Thanks for the good work :-)

Issue with `UnitOfWork` and query parameters

The EntityRepository find method does registerClean in the unit of work but every other call to UnitOfWork is made with the entity id, which is probably better.

There might be a problem when having two different instances of an entity sharing the same id though, but the problem is already here as the use the id getter in the findBy / findAll methods

DateTime : allow customer format

Today, the datetime serializer format date like this : ->format('c'), but sometimes, the API needs a custom format (SIBIL requires a Java Instant that doesn't accept anything else than Y-m-d\TH:i:s\Z).

Allow the Attribute to have an options parameters, and the datetime should use options.format value if provided

Possibility to configure API return keys

->findAll() on the AbstractClient results in an empty array.

I think this has to do with the hydra: prefix on the member key.
As far as I know the key for members on a collection is members instead of hydra:member

see: convertList method in the AbstractClient class.

Type hinting (PHPDoc and method signatures)

Type hinting is a bit off on most classes of this project, which makes it difficult to use in recent IDEs.

class EntityRepository
{
// ...
    /**
     * @object REST Client
     */
    protected $restClient;

    /**
     * @var SDK object
     */
    protected $sdk;
// ...
    /**
     * EntityRepository constructor
     *
     * @param object $sdkClient - the client to connect to the datasource with
     * @param object $restClient - client to process the http requests
     * @param string $entityName The entiy to work with
     */
    public function __construct($sdkClient, $restClient, $entityName)
    {
        $this->sdk = $sdkClient;
        $this->restClient = $restClient;
        $this->entityName = $entityName;
    }
// ...
}

I could take care of this by adding/fixing PHPDoc blocks and methods signatures as such (for example):

class EntityRepository
{
// ...
    /**
     * @var RestClient
     */
    protected $restClient;

    /**
     * @var SdkClient
     */
    protected $sdk;
// ...
    /**
     * EntityRepository constructor
     *
     * @param SdkClient  $sdkClient  The client to connect to the datasource with
     * @param RestClient $restClient The client to process the http requests
     * @param string     $entityName The entity to work with
     */
    public function __construct(SdkClient $sdkClient, RestClient $restClient, $entityName)
    {
        $this->sdk = $sdkClient;
        $this->restClient = $restClient;
        $this->entityName = $entityName;
    }
// ...
}

Just let me know if it's ok with you :)

Persisting an entity with a ManyToOne relation does not convert related entity as IRI

We have the following entity classes:

<?php

namespace AppBundle\Entity;

use Mapado\RestClientSdk\Mapping\Annotations as Rest;

/**
 * @Rest\Entity(key="articles")
 */
class Article
{
    /**
     * @Rest\Id
     * @Rest\Attribute(name="id", type="string")
     */
    private $id;

    /**
     * @Rest\ManyToOne(name="section", targetEntity="Section")
     */
    private $section;

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getId()
    {
        return $this->id;
    }

    public function setSection(Section $section)
    {
        $this->section = $section;
    }

    public function getSection()
    {
        return $this->section;
    }
}

and

<?php

namespace AppBundle\Entity;

use Mapado\RestClientSdk\Mapping\Annotations as Rest;

/**
 * @Rest\Entity(key="sections")
 */
class Section
{
    /**
     * @Rest\Id
     * @Rest\Attribute(name="id", type="string")
     */
    private $id;

    /**
     * @var string
     *
     * @Rest\Attribute(name="title", type="string")
     */
    private $title;

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getId()
    {
        return $this->id;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getTitle()
    {
        return $this->title;
    }
}

When we persist an entity like this:

// $section is a valid and existing entity fetched from the API.

$article = new Article();
$article->setSection($section);

$articleRepository = $sdk->getRepository('articles');
$articleRepository->persist($article);

Then the HTTP call to the API is like this:

Path: POST http://domain.tld/articles

Parameters: { "json": { "section": "946c3a2a-e36a-11e6-b8b0-0242ac110002", "title": "test" }, "version": "1.0", "headers": { "Accept-Language": "en-US,en;q=0.5" } } 

Notice how the "section" key is "946c3a2a-e36a-11e6-b8b0-0242ac110002" instead of "/sections/946c3a2a-e36a-11e6-b8b0-0242ac110002"

I think the fix could be to modify the Serializer::recursiveSerialize method, around line 189, by replacing:

if ($data->getId()) {
    $data = $data->getId();
} elseif (...) {

with:

if ($data->getId()) {
    $hydrator = $this->sdk->getModelHydrator();
    $data = $hydrator->convertId($data->getId(), $relation->getTargetEntity());
} elseif (...) {

support of partial entities

Hi,

In an attempt to optimize a CMS using the mapado REST client SDK, I tried implementing HTTP-based normalization/denormalization groups on the API I'm using, i.e. :

GET /articles/1234

would return a complete entity like this:

{
  	"id": 1234,
  	"body": "<p>Article body</p>",
  	"template": "article",
  	"section": 2345,
  	"title": "Article title",
  	"sponsor": null,
  	"authors": [
  		456,
  		567
  	],
  	"tags": [
  		567,
  		678
  	],
  	"status": "PUBLISHED",
  	"createdAt": "2017-09-21T15:28:10-04:00",
  	"modifiedAt": "2017-10-23T15:40:04-04:00"
  }

While

GET /articles/1234?_groups[]=bare

would return only a partial entity like this:

{
  	"id": 1234,
  	"title": "Article title"
  }

Unfortunately, the REST client calls every setter on the entity, and for values which were not returned by the API, attempts to set NULL values with setters which don't allow them, causing fatal errors.

A possible "fix" / solution would be to skip setter calls for which the corresponding property was not provided in the API response.

Does it make sense?

Support for php 5.4

At the moment your only lib which requires a minimum of php 5.5 is the guzzle client.
Could you run the tests with guzzle ~5.3.0 also, to check if the SDK still works on PHP 5.4?

Proxy initializer function bug

Hi dude, how are you?
i found this really weird bug.
When i call a method on a Proxy, (proxy because Oficina its a subresource), in the controller like this:
$agenteRepository->find(20)->getOficina()

object(ProxyManagerGeneratedProxy_PM_\App\Entity\Rest\Oficina\Generated183fa80ff3d071671b476b73d35b700e)[2419]
private 'initializer9b768' =>
object(Closure)[2371]
public 'static' =>
array (size=4)
'sdk' =>
object(Mapado\RestClientSdk\SdkClient)[532]
...
'classMetadata' =>
object(Mapado\RestClientSdk\Mapping\ClassMetadata)[562]
...
'id' => string '/api/oficinas/1' (length=15)
'proxyModelName' => string 'App\Entity\Rest\Oficina' (length=23)
public 'this' =>
object(Mapado\RestClientSdk\SdkClient)[532]
protected 'restClient' =>
object(Mapado\RestClientSdkBundle\RequestAwareRestClient)[440]
...
protected 'cacheItemPool' =>
object(Symfony\Component\Cache\Adapter\ArrayAdapter)[493]
...
protected 'cachePrefix' => string 'mapado_rest_client_' (length=19)
private 'mapping' =>
object(Mapado\RestClientSdk\Mapping)[537]
...
private 'serializer' =>
object(Mapado\RestClientSdk\Model\Serializer)[531]
...
private 'modelHydrator' =>
object(Mapado\RestClientSdk\Model\ModelHydrator)[536]
...
private 'repositoryList' =>
array (size=1)
...
private 'proxyManagerConfig' =>
object(ProxyManager\Configuration)[534]
...
private 'unitOfWork' =>
object(Mapado\RestClientSdk\UnitOfWork)[526]
...
public 'parameter' =>
array (size=5)
'$proxy' => string '' (length=10)
'$method' => string '' (length=10)
'$parameters' => string '' (length=10)
'&$initializer' => string '' (length=10)
'$properties' => string '' (length=10)
private 'initializationTracker65ef4' => boolean false
private 'iri' (App\Entity\Rest\Oficina) => string '/api/oficinas/1' (length=15)
private 'numero' (App\Entity\Rest\Oficina) => null
private 'descripcion' (App\Entity\Rest\Oficina) => null
private 'finalidad' (App\Entity\Rest\Oficina) => null
private 'ofiPrgCodigo' (App\Entity\Rest\Oficina) => null
private 'baja' (App\Entity\Rest\Oficina) => null
private 'ofiUejCodigo' (App\Entity\Rest\Oficina) => null
private 'ofiModCodigo' (App\Entity\Rest\Oficina) => null
private 'codigo' (App\Entity\Rest\Oficina) => null

All the attributes of the entity are in null.
BUT! if you pass this same object to a template like this:
{{ agente.oficina.numero }}
this works.......

SO.....I investigated this and i found this:
vendor/mapado/rest-client-sdk/src/SdkClient.php:245
if (!$isAllowedMethod) {

this condition on the initializer function always return false when you call it from a controller....but i don't know why...

Do not `PUT` if Unit of work returns an empty diff

If you have this entity:

{
  "@id": "/foo/1",
  "title": "first foo"
}

and you send the same, the UnitOfWork will try to put this:

{}

Which is useless. If the unit of work returns an empty diff, we should not send the request

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.