Code Monkey home page Code Monkey logo

full-stack-fastapi-mongodb's Issues

Frontend container does not hot-reload for local development

Context

The frontend container does not support "hot reload" for local development within the container. This is because our Dockerfile does not have functionality for running a dev build. The solution would be to update the frontend/Dockerfile to have both dev and prod builds that would change based on the context it is being run from.

  • If it is being run locally, use the local build which should support hot-reload and link to local files
  • If run for production, build the production bundle without the need for hot-reload

Note

  • The current stop-gap solution is to run the frontend outside of the docker container leveraging npm install && npm run dev or yarn install && yarn dev

TypeError: CRUDUser.is_active() missing 1 required positional argument: 'user'

Error:

TypeError: CRUDUser.is_active() missing 1 required positional argument: 'user'

How To Reproduce

The Error occurs when you try to login with the /oauth route using either the admin credentials or normal user credentials, The static method to check user Active status fails with missing positional argument user.

Models are out of date with the new pydantic modeling paradigm from pydantic 2.0

Seems like this is still using the old implementation of Config for pydantic. For example:

class RefreshToken(RefreshTokenUpdate):
    class Config:
        from_attributes = True

Should now be re-written as:

from pydantic import ConfigDict

class RefreshToken(RefreshTokenUpdate):

    model_config = ConfigDict(from_attributes=True)

I believe you should be able to use Bump Pydantic to get a lot of these things fixed with minimal work

celeryworker.dockerfile exiting with code: 1

Docker compose build command exits with code: 1, line 17 - 20 in the celeryworker.dockerfile in the backend directory. Getting this response in the terminal "23.63 Environment production is not defined by project config
23.65 chmod: cannot access '/app/worker-start.sh'$'\r': No such file or directory

failed to solve: process "/bin/sh -c python -m pip install --no-cache-dir --upgrade pip "pipx==$PIPX_VERSION"\r\npipx install "hatch==$HATCH_VERSION"\r\nhatch env prune && hatch env create production\r\nchmod +x /app/worker-start.sh\r\n" did not complete successfully: exit code: 1"

Am I doing something wrong here? I definitely can be making a dumb config mistake. Default configuration to localhost.

backend exits "TypeError: type 'types.UnionType' is not subscriptable"

Hi! When I follow Quickstart instructions, the backend exits with the following error. I realized this after login didn't work so #34 might also be related.

2024-04-24 12:52:35 INFO:__main__:Initializing service
2024-04-24 12:52:35 INFO:__main__:Starting call to '__main__.init', this is the 1st time calling it.
2024-04-24 12:52:35 INFO:__main__:Service finished initializing
2024-04-24 12:52:40 Traceback (most recent call last):
2024-04-24 12:52:40   File "/app/app/initial_data.py", line 4, in <module>
2024-04-24 12:52:40     from app.db.init_db import init_db
2024-04-24 12:52:40   File "/app/app/db/init_db.py", line 3, in <module>
2024-04-24 12:52:40     from app import crud, schemas
2024-04-24 12:52:40   File "/app/app/crud/__init__.py", line 1, in <module>
2024-04-24 12:52:40     from .crud_user import user
2024-04-24 12:52:40   File "/app/app/crud/crud_user.py", line 7, in <module>
2024-04-24 12:52:40     from app.models.user import User
2024-04-24 12:52:40   File "/app/app/models/__init__.py", line 1, in <module>
2024-04-24 12:52:40     from .user import User
2024-04-24 12:52:40   File "/app/app/models/user.py", line 17, in <module>
2024-04-24 12:52:40     class User(Base):
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/odmantic/model.py", line 487, in __new__
2024-04-24 12:52:40     return super().__new__(mcs, name, bases, namespace, **kwargs)
2024-04-24 12:52:40            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/odmantic/model.py", line 405, in __new__
2024-04-24 12:52:40     cls = super().__new__(mcs, name, bases, namespace, **kwargs)
2024-04-24 12:52:40           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 178, in __new__
2024-04-24 12:52:40     set_model_fields(cls, bases, config_wrapper, types_namespace)
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 452, in set_model_fields
2024-04-24 12:52:40     fields, class_vars = collect_model_fields(cls, bases, config_wrapper, types_namespace, typevars_map=typevars_map)
2024-04-24 12:52:40                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_fields.py", line 122, in collect_model_fields
2024-04-24 12:52:40     type_hints = get_cls_type_hints_lenient(cls, types_namespace)
2024-04-24 12:52:40                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 212, in get_cls_type_hints_lenient
2024-04-24 12:52:40     hints[name] = eval_type_lenient(value, globalns, localns)
2024-04-24 12:52:40                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 224, in eval_type_lenient
2024-04-24 12:52:40     return eval_type_backport(value, globalns, localns)
2024-04-24 12:52:40            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 240, in eval_type_backport
2024-04-24 12:52:40     return typing._eval_type(  # type: ignore
2024-04-24 12:52:40            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 12:52:40   File "/usr/local/lib/python3.11/typing.py", line 382, in _eval_type
2024-04-24 12:52:40     t = t.__origin__[args]
2024-04-24 12:52:40         ~~~~~~~~~~~~^^^^^^
2024-04-24 12:52:40 TypeError: type 'types.UnionType' is not subscriptable
2024-04-24 12:52:40 Traceback (most recent call last):
2024-04-24 12:52:40   File "<frozen runpy>", line 198, in _run_module_as_main
2024-04-24 12:52:40   File "<frozen runpy>", line 88, in _run_code
2024-04-24 12:52:40   File "/app/inboard/start.py", line 134, in <module>
2024-04-24 12:52:40     run_pre_start_script(logger=logger)
2024-04-24 12:52:40   File "/app/inboard/start.py", line 30, in run_pre_start_script
2024-04-24 12:52:40     subprocess.run([process, pre_start_path], check=True)
2024-04-24 12:52:40   File "/usr/local/lib/python3.11/subprocess.py", line 571, in run
2024-04-24 12:52:40     raise CalledProcessError(retcode, process.args,
2024-04-24 12:52:40 subprocess.CalledProcessError: Command '['sh', '/app/prestart.sh']' returned non-zero exit status 1.
2024-04-24 13:04:24 INFO:__main__:Initializing service
2024-04-24 13:04:24 INFO:__main__:Starting call to '__main__.init', this is the 1st time calling it.
2024-04-24 13:04:24 INFO:__main__:Service finished initializing
2024-04-24 13:04:26 Traceback (most recent call last):
2024-04-24 13:04:26   File "/app/app/initial_data.py", line 4, in <module>
2024-04-24 13:04:26     from app.db.init_db import init_db
2024-04-24 13:04:26   File "/app/app/db/init_db.py", line 3, in <module>
2024-04-24 13:04:26     from app import crud, schemas
2024-04-24 13:04:26   File "/app/app/crud/__init__.py", line 1, in <module>
2024-04-24 13:04:26     from .crud_user import user
2024-04-24 13:04:26   File "/app/app/crud/crud_user.py", line 7, in <module>
2024-04-24 13:04:26     from app.models.user import User
2024-04-24 13:04:26   File "/app/app/models/__init__.py", line 1, in <module>
2024-04-24 13:04:26     from .user import User
2024-04-24 13:04:26   File "/app/app/models/user.py", line 17, in <module>
2024-04-24 13:04:26     class User(Base):
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/odmantic/model.py", line 487, in __new__
2024-04-24 13:04:26     return super().__new__(mcs, name, bases, namespace, **kwargs)
2024-04-24 13:04:26            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/odmantic/model.py", line 405, in __new__
2024-04-24 13:04:26     cls = super().__new__(mcs, name, bases, namespace, **kwargs)
2024-04-24 13:04:26           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 178, in __new__
2024-04-24 13:04:26     set_model_fields(cls, bases, config_wrapper, types_namespace)
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 452, in set_model_fields
2024-04-24 13:04:26     fields, class_vars = collect_model_fields(cls, bases, config_wrapper, types_namespace, typevars_map=typevars_map)
2024-04-24 13:04:26                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_fields.py", line 122, in collect_model_fields
2024-04-24 13:04:26     type_hints = get_cls_type_hints_lenient(cls, types_namespace)
2024-04-24 13:04:26                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 212, in get_cls_type_hints_lenient
2024-04-24 13:04:26     hints[name] = eval_type_lenient(value, globalns, localns)
2024-04-24 13:04:26                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 224, in eval_type_lenient
2024-04-24 13:04:26     return eval_type_backport(value, globalns, localns)
2024-04-24 13:04:26            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_typing_extra.py", line 240, in eval_type_backport
2024-04-24 13:04:26     return typing._eval_type(  # type: ignore
2024-04-24 13:04:26            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-04-24 13:04:26   File "/usr/local/lib/python3.11/typing.py", line 382, in _eval_type
2024-04-24 13:04:26     t = t.__origin__[args]
2024-04-24 13:04:26         ~~~~~~~~~~~~^^^^^^
2024-04-24 13:04:26 TypeError: type 'types.UnionType' is not subscriptable
2024-04-24 13:04:26 Traceback (most recent call last):
2024-04-24 13:04:26   File "<frozen runpy>", line 198, in _run_module_as_main
2024-04-24 13:04:26   File "<frozen runpy>", line 88, in _run_code
2024-04-24 13:04:26   File "/app/inboard/start.py", line 134, in <module>
2024-04-24 13:04:26     run_pre_start_script(logger=logger)
2024-04-24 13:04:26   File "/app/inboard/start.py", line 30, in run_pre_start_script
2024-04-24 13:04:26     subprocess.run([process, pre_start_path], check=True)
2024-04-24 13:04:26   File "/usr/local/lib/python3.11/subprocess.py", line 571, in run
2024-04-24 13:04:26     raise CalledProcessError(retcode, process.args,
2024-04-24 13:04:26 subprocess.CalledProcessError: Command '['sh', '/app/prestart.sh']' returned non-zero exit status 1.

Unused AgnosticDatabase in Method Signatures

Hi there. I've noticed that AgnosticDatabase is included in several method signatures, but it doesn't seem to be used within the methods themselves. The application appears to be functioning on AIOEngine. In my project cases, I have already removed AgnosticDatabase. If it is needed in the future, I can create a pull request to reintroduce it. Could you kindly clarify if there are plans to utilize AgnosticDatabase in the future or if it will be removed from the method signatures? Thank you.

useSearchParams() should be wrapped in a suspense boundary

I'm receiving the following error during the static page generation for /, reset-password, and login when running 'docker compose build':

28.83    Generating static pages (0/16) ...
29.55
29.55  ⨯ useSearchParams() should be wrapped in a suspense boundary at page "/reset-password". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
29.55
29.55 Error occurred prerendering page "/reset-password". Read more: https://nextjs.org/docs/messages/prerender-error
29.55
29.56  ⨯ useSearchParams() should be wrapped in a suspense boundary at page "/". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
29.56
29.56 Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error
29.56
29.56
   Generating static pages (4/16)
   Generating static pages (8/16)
29.70
29.70  ⨯ useSearchParams() should be wrapped in a suspense boundary at page "/login". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
29.70
29.70 Error occurred prerendering page "/login". Read more: https://nextjs.org/docs/messages/prerender-error
29.70
   Generating static pages (12/16)
 ✓ Generating static pages (16/16)
30.28
30.28 > Export encountered errors on following paths:
30.28 	/login/page: /login
30.28 	/page: /
30.28 	/reset-password/page: /reset-password
------
failed to solve: process "/bin/sh -c npm run build" did not complete successfully: exit code: 1

Possible error in the code base

In the /backend/app/app/schemas/base_schema.py I found what is likely to be an error in the as_db_dict property of BaseSchema class. In the set literal {"identifier, id"} the correct syntax should probably use two separate strings in the set: {"identifier", "id"}. I did local tests and it seems not to affect the properties end result because the key "identifier" is overwritten anyway in this case. But model_dump() outputs a different result when using two separated string, ie: excluding the key "identifier" from the dumped model.

class BaseSchema(BaseModel):
    @property
    def as_db_dict(self):
        to_db = self.model_dump(
            exclude_defaults=True, exclude_none=True, exclude={"identifier, id"}
        )
        for key in ["id", "identifier"]:
            if key in self.model_dump().keys():
                to_db[key] = self.model_dump()[key].hex
        return to_db

Should make use of SecretStr for any Token or Password fields

To avoid logging tokens or passwords accidentally pydantic provides a nice SecretStr model as a way to reduce these issues.

Can change instances like:

class Token(BaseModel):
    access_token: str
    refresh_token: Optional[str] = None
    token_type: str

to

from pydantic import SecretStr

class Token(BaseModel):
    access_token: SecretStr
    refresh_token: Optional[SecretStr] = None
    token_type: str

"Phantom Login" On generated app with magic link sign up

When attempting to log into a generated app, there are times where the frontend react state believes it has logged in, however, there is no auth token, nor profile data for a logged in user. The incorrect state leaves functionality "clickable" yet fails.

The believed issue stems from the auth.ts file not having completed error handling on cases where the response payload from the backend fails. Adding in errorhandleres on every function in those should resolve this problem.

(frontend) npm audit 12 vulnerabilities (4 moderate, 7 high, 1 critical)

Running npm audit returns this:

❯ npm audit
# npm audit report

ajv  <6.12.3
Severity: moderate
Prototype Pollution in Ajv - https://github.com/advisories/GHSA-v88g-cgmw-v5xw
No fix available
node_modules/tailwind/node_modules/ajv
  tailwind  *
  Depends on vulnerable versions of ajv
  Depends on vulnerable versions of body-parser
  Depends on vulnerable versions of datasette
  Depends on vulnerable versions of express
  Depends on vulnerable versions of flaschenpost
  Depends on vulnerable versions of limes
  Depends on vulnerable versions of lodash
  Depends on vulnerable versions of ws
  node_modules/tailwind

express  <=4.19.1 || 5.0.0-alpha.1 - 5.0.0-alpha.7
Severity: high
Express.js Open Redirect in malformed URLs - https://github.com/advisories/GHSA-rv95-896h-c2vc
Depends on vulnerable versions of body-parser
Depends on vulnerable versions of qs
fix available via `npm audit fix`
node_modules/express

jsonwebtoken  <=8.5.1
Severity: moderate
jsonwebtoken unrestricted key type could lead to legacy keys usage  - https://github.com/advisories/GHSA-8cf7-32gw-wr33
jsonwebtoken's insecure implementation of key retrieval function could lead to Forgeable Public/Private Tokens from RSA to HMAC - https://github.com/advisories/GHSA-hjrf-2m68-5959
jsonwebtoken vulnerable to signature validation bypass due to insecure default algorithm in jwt.verify() - https://github.com/advisories/GHSA-qwph-4952-7xr6
fix available via `npm audit fix`
node_modules/jsonwebtoken
  limes  *
  Depends on vulnerable versions of jsonwebtoken
  node_modules/limes

lodash  <=4.17.20
Severity: critical
Regular Expression Denial of Service (ReDoS) in lodash - https://github.com/advisories/GHSA-x5rq-j2xg-h7qm
Prototype Pollution in lodash - https://github.com/advisories/GHSA-4xc9-xhrj-v574
Regular Expression Denial of Service (ReDoS) in lodash - https://github.com/advisories/GHSA-29mw-wpgm-hmr9
Prototype Pollution in lodash - https://github.com/advisories/GHSA-p6mc-m468-83gw
Command Injection in lodash - https://github.com/advisories/GHSA-35jh-r3h4-6jhm
Prototype Pollution in lodash - https://github.com/advisories/GHSA-jf85-cpcp-j695
fix available via `npm audit fix`
node_modules/datasette/node_modules/lodash
node_modules/lodash
  datasette  *
  Depends on vulnerable versions of lodash
  node_modules/datasette
  flaschenpost  <=5.0.5
  Depends on vulnerable versions of lodash
  Depends on vulnerable versions of moment
  node_modules/flaschenpost

moment  <=2.29.3
Severity: high
Moment.js vulnerable to Inefficient Regular Expression Complexity - https://github.com/advisories/GHSA-wc69-rhjr-hc9g
Path Traversal: 'dir/../../filename' in moment.locale - https://github.com/advisories/GHSA-8hfj-j24r-96c4
fix available via `npm audit fix`
node_modules/moment

qs  6.5.0 - 6.5.2
Severity: high
qs vulnerable to Prototype Pollution - https://github.com/advisories/GHSA-hrpp-h998-j3pp
No fix available
node_modules/qs
  body-parser  1.18.0 - 1.18.3
  Depends on vulnerable versions of qs
  node_modules/body-parser

ws  6.0.0 - 6.2.1
Severity: moderate
ReDoS in Sec-Websocket-Protocol header - https://github.com/advisories/GHSA-6fc8-4gx4-v693
No fix available
node_modules/ws

12 vulnerabilities (4 moderate, 7 high, 1 critical)

To address issues that do not require attention, run:
  npm audit fix

Some issues need review, and may require choosing
a different dependency.

npm audit fix doesn't seem to affect this.

The 7 high and 1 critical vulnerabilities should probably be looked at, maybe there is a 'easy' way to fix?
The critical one seems to be a dependency on tailwind (note, NOT tailwindcss)
Is tailwind a mistake? I can't see where it's used, the repository haven't been updated in 5 years, there are a lot of downloads of the npm package, but I wonder how many is because they think its tailwindcss.

pydantic.errors.PydanticUserError

pydantic.errors.PydanticUserError: model_config cannot be used as a model field name. Use model_config for model configuration.

Followed alI the steps for local development but containers backend and celeryworker didn't spin up outputting the same pydantic error.

I'm on a Mac M1 Sonoma 14.4.1

Recommended way to run the docker-compose

I've been trying for a few days to run this project, but without success.
I would prefer not to run this as root as that seems unnecessary.

When i run it from a fresh cookiecutter output i get:

❯ docker-compose up -d
[+] Running 6/9
 ⠴ Network project_traefik-public    Created                                                                                                                         1.6s
 ⠴ Network project_default           Created                                                                                                                         1.5s
 ✔ Container project-backend-1       Started                                                                                                                         1.5s
 ✔ Container project-mongodb-1       Started                                                                                                                         1.5s
 ✔ Container project-celeryworker-1  Started                                                                                                                         0.8s
 ✔ Container project-flower-1        Started                                                                                                                         1.5s
 ⠼ Container project-proxy-1         Starting                                                                                                                        1.5s
 ✔ Container project-frontend-1      Started                                                                                                                         0.9s
 ✔ Container project-queue-1         Started                                                                                                                         0.9s

Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:80 -> 0.0.0.0:0: listen tcp 0.0.0.0:80: bind: permission denied

I've tried a ton of things, remapping '8888:80' etc etc which didn't accomplish the things I wanted it to do. I would still prefer to serve backend at 'localhost/api'
Adding

 cap_add:
      - CAP_NET_BIND_SERVICE

doesn't help at all. Still same message.
The only thing I can think of is to assign the privileges to the docker process for cap_net_bind_service (I haven't tried this yet)
or running the docker-compose up -d as root.
Both solutions doesn't seem optimal, especially when I need it to run on a production service. Would prefer that the process or the user running it doesn't have elevated privileges.

If the best way is just to run traefik on 8080 and then bind the backend to 8080 (or something similar) and then run the change .env in frontend to:
NEXT_PUBLIC_API_URL=http://localhost:8080/api/v1

I'm pretty new to docker, so there might be a obvious solution to this, but googling and ChatGPT hasn't been able to help me

EDIT:
I tried updating the docker-compose.override.yml to look like this:

version: "3.7"
services:
  proxy:
    ports:
      # - "80:80"  # Removed this
      - "8090:8080"
    command:
      -------
  backend:
    ports:
      - "8888:80" # changed from "8888:8888" --> "8888:80"

This seem to work, I still can't access anything when visiting:
http://localhost:8888/api/
It just returns:
image

same for http://localhost:8888/api/v1

but when I use the frontend (after updating .env.local to localhost:8888) I get a response from the server:
{"access_token":"**********","refresh_token":"**********","token_type":"bearer"}
I didn't change the access_token or refresh_token, they came like that, I don't know if that's what's supposed to be?

I've also tested with a wrong password and that doesn't pass validation, so the authentication is happening on the backend with a connection to the database.

EDIT 2:
I found the correct urls for the documentation by just thinking a little, so I have access to the documentation on
127.0.0.1:8888/docs / redoc
But the main question still stands regarding running port 80 in docker

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.