GithubHelp home page GithubHelp logo

bettertyped / hyper-fetch Goto Github PK

View Code? Open in Web Editor NEW
1.0K 4.0 27.0 9.87 MB

⚡ Fetching and realtime data exchange framework.

Home Page: https://hyperfetch.bettertyped.com/

License: Apache License 2.0

TypeScript 99.00% Shell 0.10% JavaScript 0.91%
fetch xhr javascript graphql offline persistence cache builder typescript nextjs

hyper-fetch's Introduction

Hyper Fetch

Framework for fetching and realtime data exchange.

Documentation | Quick Start | Guides


Hyper Fetch is unique fetching and realtime data-exchange framework meticulously crafted to prioritize simplicity and efficiency. Its typesafe design and user-friendly interface ensure a seamless integration experience, whether you're working on the browser or the server. Next-generation features streamlines architecture creation, grants access to the request lifecycle, and empowers rapid development of new components and functionalities, all while facilitating real-time data exchange.


Premium sponsor banner

Premium sponsor banner

Key Features

🔮 Simple setup - Read more

🎯 Easy cancellation - Read more

Deduplicate similar requests - Read more

🚀 Queueing - Read more

💎 Response Caching - Read more

🔋 Offline First - Read more

📡 Built-in fetcher - Read more

🎟 Authentication - Read more

🔁 Smart Retries - Read more

Help me keep working on this project ❤️

Installation

The easiest way to get the latest version of Hyper Fetch is to install it via yarn or npm.

npm install --save @hyper-fetch/core
or
yarn add @hyper-fetch/core
npm install --save @hyper-fetch/sockets
or
yarn add @hyper-fetch/sockets
npm install --save @hyper-fetch/core @hyper-fetch/react
or
yarn add @hyper-fetch/core @hyper-fetch/react

Premium sponsor banner

Premium sponsor banner

Packages

Package Stats
Hyper Fetch
Sockets
React
Firebase
Firebase Admin
GraphQL
Axios
Codegen Openapi

Examples

Simple Setup

import { Client } from "@hyper-fetch/core";

// Setup our connection to the server
export const client = new Client({ url: "http://localhost:3000" });

// Create reusable requests for later use
export const postData = client.createRequest<ResponseType, RequestType, LocalErrorType, QueryParamsType>()({
  method: "POST",
  endpoint: "/data/:accountId",
});

export const getData = client.createRequest<ResponseType, RequestType, LocalErrorType, QueryParamsType>()({
  method: "GET",
  endpoint: "/user",
});

Fetching

Executing previously prepared requests is very simple. We can do this using the send method.

const { data, error, status } = await getData.send();

Mutation request

We can attach the data to the request with methods before sending it to the server. This is helpful for building our request and attaching data to it which can be helpful when we need to create it in a few steps from data obtained during some process.

// Set the information to request (methods return request clone - NOT mutating the source)
const request = postData
  .setParams({ accountId: 104 }) // Set Params
  .setQueryParams({ paramOne: "test", paramTwo: "test2" })
  .setData({ name: "My new entity", description: "Some description" }) // Add payload data
  .send();

We can also pass them directly to the send method, which will add them to the request at once.

// OR pass dynamic data directly to '.send' method
const { data, error, status } = await postData.send({
  params: { accountId: 104 },
  data: { name: "My new entity", description: "Some description" },
  queryParams: { paramOne: "test", paramTwo: "test2" },
});

Premium sponsor banner

Premium sponsor banner

React

Fetch with lifecycle

Show me example
import { useFetch } from "@hyper-fetch/react";

// Lifecycle fetching
const { data, error, loading, onSuccess, onError } = useFetch(getData);

onSuccess((data) => {
  console.log(data);
});

onError((error) => {
  console.log(error);
});

Manually trigger requests

Show me example
import { useSubmit } from "@hyper-fetch/react";

const { submit, data, error, submitting, onSubmitSuccess, onSubmitError } = useSubmit(request);

onSuccess((data) => {
  console.log(data);
});

onError((error) => {
  console.log(error);
});

return <button onClick={() => submit()}>Trigger request!</button>;

Pass dynamic data to submit method

Show me example
import { useSubmit } from "@hyper-fetch/react";

const { submit, data, error, submitting, onSubmitSuccess, onSubmitError } = useSubmit(request);

onSuccess((data) => {
  console.log(data);
});

onError((error) => {
  console.log(error);
});

return (
  <button
    onClick={() =>
      submit({
        params: { accountId: 104 },
        data: { name: "My new entity", description: "Some description" },
        queryParams: { paramOne: "test", paramTwo: "test2" },
      })
    }
  >
    Trigger request!
  </button>
);

Use submit promise response

Show me example
import { useSubmit } from "@hyper-fetch/react";

// Manual triggering
const { submit, data, error, submitting, onSubmitSuccess, onSubmitError } = useSubmit(request);

onSuccess((data) => {
  console.log(data);
});

onError((error) => {
  console.log(error);
});

const handleSubmit = (values: ValuesType, { setSubmitting }: FormikHelpers) => {
  const { data, error, status } = await submit(); // Submit method returns data!
  setSubmitting(false);
  if (data) {
    notification.success("Done!", data);
  } else {
    notification.success("Error!", error);
  }
};

return <Form onSubmit={handleSubmit}>...</Form>;

💖 Our sponsors

My Sponsors

hyper-fetch's People

Contributors

albelewandowski avatar dependabot[bot] avatar exmirai avatar gerasnyx avatar lukashirt avatar prc5 avatar schalkventer avatar snyk-bot avatar spezzino avatar th3fallen avatar yeasiin 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

hyper-fetch's Issues

Not working with Nuxt 3

Describe the bug
Not sure if this is Nuxt or Hyper Fetch related issue.
Importing the Client will results to default is not a constructor in Nuxt.
Any help would be much appreciated. Thank you.

To Reproduce
Steps to reproduce the behavior:

  1. Go to hyperfetch-nuxt-demo
  2. See error on the preview

Expected behavior
No error should happen.

Screenshots
see hyperfetch-nuxt-demo

Desktop (please complete the following information):
N/A

Smartphone (please complete the following information):
N/A

Additional context
N/A

useFetch: Disabling or stop refreshing a request is not possible once refresh = true has been set

Hello again,

in my current project the user clicks on a button, which starts some long running backend process via an API call.
Now I wanted to make use of the refreshing feature mentioned here, to get some status update from the API:

Once the backend task finishes, the API will respond with some special data, which I wanted to use to stop polling.
But I am unable to stop refreshing once it has been started. I tried setting refresh to false, and also tried setting disabled to true.

I think refresh here (https://github.com/BetterTyped/hyper-fetch/blob/ec9542266ad900560404464ee8443cea7ac1ffee/packages/react/src/hooks/use-fetch/use-fetch.hooks.ts#L102C10-L102C17) has not access to latest value.

Is this a bug? Or am I doing something wrong?

I have created an example here: https://codesandbox.io/s/hyper-fetch-stop-refresh-fzgglc?file=/src/App.tsx
Click the button to start polling for updates. After 5 seconds, polling should stop, but it does not. You can see that in the network tab of the dev tools.

Best
Stefan

Typescript build error when using setDataMapper and trying to set dynamic data in submit function

Hey, in a TypeScript project I was following the Data Mapping Guide (https://hyperfetch.bettertyped.com/guides/Basic/Data%20Mapping/#set-payload-data-mapper) to transform some data into FormData.

I need to do it dynamically, so I also followed the Passing data and params guide (https://hyperfetch.bettertyped.com/docs/React/useSubmit/#passing-data-and-params) and tried to add my data to the submit function of the useSubmit hook.

But I am running in a TypeScript build error.
Can you assist in any way? What am I doing wrong?

Type 'string' is not assignable to type 'never'.ts(2322)

I prepared some CodeSandbox here: https://codesandbox.io/s/hyper-fetch-setdatamapper-dynamic-params-pekl0p?file=/src/App.tsx:714-726

Thanks in advance!
Stefan

[Docs] Error Handling

Is your feature request related to a problem? Please describe.
It would be great to have some documentation surrounding handling errors. particularly errors when not using the typical async/await syntax as currently i dont think .send will return a rejected promise. ( i could be wrong on that though)

Allow removing request / response interceptors

Is your feature request related to a problem? Please describe.
In my React app I would like to add some visual activity log for API requests / responses similar to the network tab of the browser's developer tools. The app user should be globally notified about API errors and should not need to open the developer tools.

I saw that I can use client.onRequest and client.onResponse methods to add some listeners.

Now I wanted to put this into a custom React hook. I have added the listeners inside of some useEffect hook, but it seems that I am not able to do some cleanup, because there is no way to remove the listeners yet, right?

import { useEffect, useState } from 'react';

import { client } from './client-hyperfetch';

export type ApiRequest = {
  endpoint: string;
  method: 'GET' | 'PUT' | 'POST' | 'DELETE';
  queryParams: { [key: string]: string };
  data: { [key: string]: any };
};

export type ApiRequestWithResponse = ApiRequest & {
  response: {
    status: number | null;
  }
};

export function useInspectApiActivity() {
  const [pendingRequests, setPendingRequests] = useState<ApiRequest[]>([]);
  const [requests, setRequests] = useState<ApiRequestWithResponse[]>([]);

  useEffect(() => {
    client.onRequest(async (request) => {
      setPendingRequests((pendingRequests) => [...pendingRequests, {
        endpoint: request.endpoint,
        method: request.method,
        queryParams: request.queryParams,
        data: request.data,
      }]);

      return request;
    });

    client.onResponse(async (response, request) => {
      setRequests((existingRequests) => [...existingRequests, {
        endpoint: request.endpoint,
        method: request.method,
        queryParams: request.queryParams,
        data: request.data,
        response: {
          status: response.status,
        },
      }]);

      // TODO: remove request from pendingRequests

      return response;
    });

    return () => {
      // I would like to remove the listeners here, but I don't know how to do that.
    };
  }, []);

  return {
    pendingRequests,
    requests,
  };
}

Is there some way to remove the listeners, or would you recommend another approach?

Not working with Sveltekit

Describe the bug
Not working with SvelteKit.

To Reproduce
Steps to reproduce the behavior:

  1. Go to this repository on stackblitz
  2. Check the error in the browser console
TypeError: import_events4.default is not a constructor
  1. Uncomment this code in page.js
// const [data, error, status] = await getData.send();
  1. New error occurs in terminal
ReferenceError: window is not defined

Screenshots
hyper-fetch

Additional context
There are few demos and the documents is not sufficient to start working with. Thank you!

The `disabled` option for `useFetch` ignored

Describe the bug
I was expecting to halt the query until the expression would evaluate true. Instead the fetch appears to always run, no matter what I pass to this param.

To Reproduce

const { data, error, loading } = useFetch(getSpeaker.setParams({ speaker: el.dataset.speaker }), {
    disabled: !showDrawer,
    refetchOnFocus: false,
});

Expected behavior
I was expecting this to behave similarly to react-query, where the fetch will only happen once disabled evaluates to true. Is that a fair assumption?

Desktop (please complete the following information):

  • OS: macOS
  • Browser: Chrome

Additional context
Add any other context about the problem here.

Settings for Increasing the request default timeout (default adapter)

Is your feature request related to a problem? Please describe.
Hi, I've noticed that a request get cancelled If it takes more than 5 seconds to response.
Can't find the correct configuration for this one here.

Is there any way I can increase the default timeout ?

In the browser adapter (even on the server), I can see the default timeout but I'm not really sure If this is the reason.

xhr.timeout = defaultTimeout;

Any help would be much appreciated. Thank you.

fetchOnMount option

The fetchOnMount option on useFetch don't work correctly. I set the option to false but the request is sent
const { data, success, error, refetch, setData } = useFetch( getSearchSuggestionRequest.setQueryParams({ q: value }), { fetchOnMount: false, } );

React Native: The package at "node_modules/@hyper-fetch/core/dist/index.cjs.js" attempted to import the Node standard library module "http".

Describe the bug
I am unable to get hyper-fetch to work with React Native + Expo

To Reproduce
Steps to reproduce the behavior:

  1. npx create-expo-app my-app
import { StatusBar } from 'expo-status-bar'
import { StyleSheet, Text, View } from 'react-native'

import { Client } from '@hyper-fetch/core'
import { useFetch } from '@hyper-fetch/react'

export const client =
  new Client() <
  ServerErrorType >
  {
    url: 'http://localhost:3000',
  }

const getStorage = client.createRequest({
  method: 'GET',
  path: '/storage',
})

export default function App() {
  const { data, loading } = useFetch(getStorage)
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style='auto' />
      <Text>{loading ? 'Loading...' : data.toString()}</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
})
  1. The package at "node_modules/@hyper-fetch/core/dist/index.cjs.js" attempted to import the Node standard library module "http".

Expected behavior
Either it works out of the box, or have the documentation list the configuration steps to avoid this

Support for Hypertext Application Language (HAL) resource links

Hi, in my current project, I am asked to use HAL resource links to load more items for a resource.

These resource links contain a full URL. The problem is, that the Hyper Fetch client already contains a baseURL for all request, which then ends up being prepended to the full URL of the resource links.

I would like to know, if there already is a way to request these resource URLs using the same client and without modifying the URL before the request is made by the HyperFetch client.

For example, imagine there is a books resource and I would like to show a paginated list of books. Requesting the books resource, the API would response with something like this:

{
  "_links":{
    "self":{
      "href":"https://my.api/books?page=1&size=10&sort=desc"
    },
    "next":{
      "href":"https://my.api/books?page=2&size=10&sort=desc"
    },
    "first":{
      "href":"https://my.api/books?page=1&size=10&sort=desc"
    },
    "last":{
      "href":"https://my.api/books?page=4&size=10&sort=desc"
    }
  },
  "_embedded":{
    "books":[
      {
        "id": 0,
        "_links":{
          "self":{
            "href":"https://my.api/books/0"
          }
        }
      },
      ...
    ]
  },
  "page":{
    "size":10,
    "totalElements":35,
    "totalPages":4,
    "number":1,
    "requestedPageSize":10
  }
}

After getting the response, I would like to grab the URL of _links.next.href and request the next books from the API.

Is there any way to do this with HyperFetch without replacing the base URL of this URL string?

Issue with typescript/vscode finding types

Describe the bug
Issue with typescript/vscode finding types

To Reproduce
After installing via: npm i @hyper-fetch/core, I get the following error message in vscode:

vsc

Looking at the hyper-fecth package.json after installation, the exports section looks like this:

  "exports": {
    ".": {
      "types": {
        "import": "./index.d.ts"
      },
      "browser": {
        "require": "./dist/browser/index.cjs.js",
        "import": "./dist/browser/index.esm.js"
      },
      "default": {
        "require": "./dist/index.cjs.js",
        "import": "./dist/index.esm.js"
      }
    },
    "./package.json": "./package.json"
  },

It looks like "import": "./index.d.ts" should in fact be "import": "./dist/index.d.ts"

Expected behavior
It should find the types.

Desktop (please complete the following information):

  • OS: Debian Bullseye
  • Browser NA
  • Version 5.7.1

built-in send() function should return properly typed data / error objects

Hi, in my latest TypeScript project, I needed to call a method that should dispatch the actual request using the built-in send() function mentioned in the docs here: https://hyperfetch.bettertyped.com/docs/guides/basic/dispatching/

Unfortunately, the returned data and error objects are of type any, which makes it hard to work on the result.
What am I doing wrong? How can I fix it?

I have prepared a CodeSandbox here: https://codesandbox.io/s/hyper-fetch-send-not-providing-typed-result-0pc3kw?file=/src/App.tsx

Best
Stefan

setQueryParams doesn't support nested object

Describe the bug
Hi, Is it possible to support nested object on setQueryParams without using JSON.stringify by default?
Or this is not a good practice?

Here's the example results when nested object was passed

filter: [object Object]

Any help would be much appreciated. Thank you.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://stackblitz.com/edit/hyperfetch-nuxt-demo-xhr9qg?file=pages%2Findex.vue
  2. Click on Fetch button
  3. Open inspect element
  4. See Network tab > Fetch/XHR
  5. Find repositories request
  6. Check its Payload

Expected behavior
Display the actual object not [object Object]

Feature `cancelable` doesn't work

Describe the bug
Feature cancelable doesn't work. Or maybe I misunderstood how it should work.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://codesandbox.io/s/wizardly-varahamihira-stnco7?file=/src/index.ts
  2. Open devtools
  3. Reload the page
  4. There are four requests to https://63d90093baa0f79e09b2f14c.mockapi.io/hyper-fetch/users

Expected behavior
There is only one request to https://63d90093baa0f79e09b2f14c.mockapi.io/hyper-fetch/users.

Screenshots
Снимок экрана 2023-01-31 в 19 05 00

Additional context
There are also a few weird moments:

  • In CodeSandbox I see TypeScript error Cannot find module '@hyper-fetch/core' or its corresponding type declarations for some reason.
  • The returned type of send() method is any. Why?

419 status with laravel breeze and nuxt

Describe the bug
I'm trying to use HyperFetch in one my projects. When I use the code below trying to login I get 419 unknown status. But it is working fine with axios and nuxt's useFetch.

To Reproduce
Steps to reproduce the behavior:
async function handleLogin() {
const client = new Client({ url: "http://localhost:8000" });

	const cookie = client.createRequest()({
		endpoint: "/sanctum/csrf-cookie",
		method: "GET",
		options: { withCredentials: true },
	});
	await cookie.send();

	const token = useCookie("XSRF-TOKEN");

	type ResponseType = { token: string; refreshToken: string };
	type RequestType = { email: string; password: string };

	const postLogin = client.createRequest<ResponseType, RequestType>()({
		method: "POST",
		endpoint: "/login",
		headers: {
			["X-XSRF-TOKEN"]: String(token.value),
		},
	});

	const { data, error, status } = await postLogin.send({
		data: {
			email: loginForm.email,
			password: loginForm.password,
		},
	});

Expected behavior
A clear and concise description of what you expected to happen.

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

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Support Angular, Svelte, Vue and others.

Is your feature request related to a problem? Please describe.
This is on the homepage.
For any Javascript / Typescript environment like Node.js, React, Angular, Svelte, Vue and others.

Additional context
There is a React adapter but no other information about other frameworks. Is this really framework agnostic? Do we need adapters?

ResponseMapper in combination with useFetch

First of all, I wanna say that I like hyper-fetch a lot!! Especially for the offline use-cases we're about to tackle, it seems the perfect solution.

Anyways, I found this inconsistency when creating a request. As by the documentation, you can append a response mapper. Here's an example:

export const getUsers = client
  .createRequest<ObjectWithUsers>()({
    method: "GET",
    endpoint: "/users",
  })
  .setResponseMapper(async (response) => {
    if (response.data) {
      return {
        ...response,
        data: {
           ...response.data,
           users: response.data.map((user) => new User(user));
        }
      };
    }
    return response;
  });

When using this request in a useFetch hook afterwards, I observe the following:

const { data, error, loading, onSuccess } = useFetch(getUsers);
  • data: data contains the mapped response of getUsers (as expected).
  • onSuccess: the request provided to your callback in onSuccess does not contain the mapped data.

Now I read that the responses are cached in their "original" form, but I would expect that since "data" and "onSuccess" are based on the same request definition (i.e. getUsers), they would both be provided with the same response.

setData not working on v4

Describe the bug
I've noticed that the setData method on V4 is not working as expected. When I inspect the browser, I am unable to see the payload request.

v3 works fine.

Thank you.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://stackblitz.com/edit/hyperfetch-nuxt-demo-xhr9qg?file=pages%2Findex.vue
  2. Click on the fetch button
  3. Inspect element -> go to Network tab -> select the "repositories" (404)
  4. No payload included

Expected behavior
Payload should be there no matter what the response status is.

Dependent requests does not seem to be reactive

Describe the bug
In my NextJS application, I wanted to use the useFetch hook to fetch some data from the API. I needed to grab some URL parameter from the router. As this parameter was undefined during the first render cycle, I tried to set up some dependent request like it is shown in the documentation.

const DetailPage: NextPageWithLayout<DetailPageProps> = (props) => {
	const router = useRouter();
	const { postId } = router.query;

	const { data, loading, error } = useFetch(getPost.setParams({ postId }), {
		disabled: !postId
	});

	...

	return <div>...</div>;
}

Unfortunately the command I passed to useFetch was never executed, once the postId was ready.

To Reproduce
I have reproduced this behaviour in the following CodeSandbox:
https://codesandbox.io/s/hyper-fetch-usefetch-disabled-not-reactive-c4zfi8?file=/src/App.js

There is some isFetchPostsDisabled property that is set to false after 1 second, but the command does not get executed.
Maybe I am misunderstanding something?

I needed to work around this issue by creating some wrapper component, that I only include once the isFetchPostsDisabled is set to false, but this is not a real dependent request anymore.
https://codesandbox.io/s/hyper-fetch-usefetch-disabled-not-reactive-fixed-using-a-middleware-component-7mq6bj?file=/src/App.js

Expected behavior
Once the "disabled" property turns to false, I expect the command to be executed.

I was hoping you could help me a bit here.
Maybe I am misunderstanding something?

Regards,
Stefan

Nuxt 3 `default is not a constructor`

Describe the bug
Related to #37

I still getting default is not a constructor. Example here https://stackblitz.com/edit/hyperfetch-nuxt-demo?file=pages%2Findex.vue
Updated the hyper-fetch to 3.3.0
Any idea ?
Any help would be much appreciated. Thank you.

To Reproduce
Steps to reproduce the behavior:

  1. Go to hyperfetch-nuxt-demo
  2. See error on the preview

Expected behavior
No error should happen.

Screenshots
see hyperfetch-nuxt-demo

Desktop (please complete the following information):
N/A

Smartphone (please complete the following information):
N/A

Additional context
N/A

Nuxt 3 - ReferenceError: XMLHttpRequest is not defined

Describe the bug
In Nuxt 3, running the request on the server side returns ReferenceError: XMLHttpRequest is not defined.
Is it possible to run a request on the server side ?
Any help would be much appreciated. Thank you.

To Reproduce
Steps to reproduce the behavior:

  1. Go to hyperfetch-nuxt-demo
  2. Check the logs on the Terminal

Expected behavior
No error should display

Screenshots
N/A

Desktop (please complete the following information):
N/A

Smartphone (please complete the following information):
N/A

Additional context
"nuxt": "3.2.0"
"@hyper-fetch/core": "^3.3.1"

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.