From fa89353525f3c2875728ea345912effe3416c9c8 Mon Sep 17 00:00:00 2001 From: Nikolai R Kristiansen Date: Sat, 30 Oct 2021 16:54:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20basic=20graphql=20API=20using?= =?UTF-8?q?=20strawberry=20=F0=9F=8D=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ Add allProducts query --- .gitignore | 12 +-- bbssite/urls.py | 22 ++--- docker-compose.yml | 19 +++++ frontend/package.json | 1 + frontend/src/App.module.css | 41 +--------- frontend/src/App.tsx | 44 ++-------- frontend/src/index.module.css | 13 --- frontend/src/main.tsx | 1 - frontend/src/typings.d.ts | 5 ++ main/api/schema.py | 20 +++++ poetry.lock | 149 +++++++++++++++++++++++++++++++++- pyproject.toml | 2 + 12 files changed, 215 insertions(+), 114 deletions(-) create mode 100644 docker-compose.yml delete mode 100644 frontend/src/index.module.css create mode 100644 frontend/src/typings.d.ts create mode 100644 main/api/schema.py diff --git a/.gitignore b/.gitignore index c4fc3c0..dd84108 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,9 @@ local_settings.py db.sqlite3 static/.sass-cache uploads/[^.]* -venv -node_modules -bower_components -.idea -/CACHE -media +venv/ +node_modules/ +.idea/ +CACHE/ +media/ +tmp/ \ No newline at end of file diff --git a/bbssite/urls.py b/bbssite/urls.py index b9e9be9..37effd7 100755 --- a/bbssite/urls.py +++ b/bbssite/urls.py @@ -1,12 +1,12 @@ from django.conf import settings +from django.conf.urls.static import static from django.contrib import admin from django.contrib.auth.views import LoginView, LogoutView -from django.contrib.staticfiles.urls import staticfiles_urlpatterns -from django.contrib.staticfiles.views import serve from django.urls import path, re_path, include +from strawberry.django.views import GraphQLView from main import urls as main_urls - +from main.api.schema import schema admin.autodiscover() @@ -16,19 +16,11 @@ urlpatterns = [ path( "accounts/logout/", LogoutView.as_view(), - name="django.contrib.auth.views.logout", + name="django.contrib.auth.views.logout" ), path("admin/", admin.site.urls), + path("graphql/", GraphQLView.as_view(schema=schema)), ] -urlpatterns += staticfiles_urlpatterns() -if settings.DEBUG: - urlpatterns += [ - re_path( - r"^media/(?P.*)$", - serve, - { - "document_root": settings.MEDIA_ROOT, - }, - ) - ] +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e8e02b1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' +services: + mysql: + image: mysql + environment: + MYSQL_ROOT_PASSWORD: dev + MYSQL_DATABASE: bbs + + ports: + - "3306:3306" + volumes: + - mydata:/var/lib/mysql + +networks: + default: + driver: bridge + +volumes: + mydata: diff --git a/frontend/package.json b/frontend/package.json index 7a0dab6..edd2b90 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,6 +2,7 @@ "name": "bbs", "private": true, "scripts": { + "start": "vite", "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", diff --git a/frontend/src/App.module.css b/frontend/src/App.module.css index 8da3fde..b48daf4 100644 --- a/frontend/src/App.module.css +++ b/frontend/src/App.module.css @@ -1,42 +1,7 @@ .App { - text-align: center; } -.App-logo { - height: 40vmin; +.logo { + width: 100px; pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -button { - font-size: calc(10px + 2vmin); -} +} \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 79f8325..84c7ac6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,43 +1,13 @@ -import { useState } from 'react' -import logo from './brick.svg' -import './App.css' +import React from 'react' + +import logo from './assets/brick.svg'; + +import styles from './App.module.css' function App() { - const [count, setCount] = useState(0) - return ( -
-
- logo -

Hello Vite + React!

-

- -

-

- Edit App.tsx and save to test HMR updates. -

-

- - Learn React - - {' | '} - - Vite Docs - -

-
+
+ logo
) } diff --git a/frontend/src/index.module.css b/frontend/src/index.module.css deleted file mode 100644 index ec2585e..0000000 --- a/frontend/src/index.module.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 606a3cf..432dac6 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,6 +1,5 @@ import React from 'react' import ReactDOM from 'react-dom' -import './index.css' import App from './App' ReactDOM.render( diff --git a/frontend/src/typings.d.ts b/frontend/src/typings.d.ts new file mode 100644 index 0000000..fda56a6 --- /dev/null +++ b/frontend/src/typings.d.ts @@ -0,0 +1,5 @@ +declare module "*.svg" { + const content: any; + export default content; +} +declare module "*.module.css"; \ No newline at end of file diff --git a/main/api/schema.py b/main/api/schema.py new file mode 100644 index 0000000..b08978e --- /dev/null +++ b/main/api/schema.py @@ -0,0 +1,20 @@ +import strawberry +from strawberry_django import auto + +from main import models + + +@strawberry.django.type(models.Product) +class Product: + id: auto + name: auto + sale_price_int: auto + sale_price_ext: auto + + +@strawberry.type +class Query: + all_products: list[Product] = strawberry.django.field() + + +schema = strawberry.Schema(query=Query) diff --git a/poetry.lock b/poetry.lock index 8590f0c..76993c4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -58,6 +58,14 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +category = "main" +optional = false +python-versions = "*" + [[package]] name = "certifi" version = "2021.10.8" @@ -81,7 +89,7 @@ unicode_backport = ["unicodedata2"] name = "click" version = "8.0.3" description = "Composable command line interface toolkit" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -92,7 +100,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -158,6 +166,14 @@ python-versions = "*" [package.dependencies] requests = "*" +[[package]] +name = "graphql-core" +version = "3.1.6" +description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +category = "main" +optional = false +python-versions = ">=3.6,<4" + [[package]] name = "gunicorn" version = "20.1.0" @@ -263,6 +279,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pygments" +version = "2.10.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "pyparsing" version = "2.4.7" @@ -292,6 +316,28 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-multipart" +version = "0.0.5" +description = "A streaming multipart parser for Python" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.4.0" + [[package]] name = "pytz" version = "2021.3" @@ -326,6 +372,17 @@ urllib3 = ">=1.21.1,<1.27" socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +[[package]] +name = "sentinel" +version = "0.3.0" +description = "Create sentinel objects, akin to None, NotImplemented, Ellipsis" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[package.extras] +varname = ["varname (>=0.1)"] + [[package]] name = "sentry-sdk" version = "1.4.3" @@ -355,6 +412,14 @@ sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] tornado = ["tornado (>=5)"] +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "sqlparse" version = "0.4.2" @@ -363,6 +428,47 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "strawberry-graphql" +version = "0.85.1" +description = "A library for creating GraphQL APIs" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +cached-property = ">=1.5.2,<2.0.0" +click = ">=7.0,<9.0" +graphql-core = ">=3.1.0,<3.2.0" +pygments = ">=2.3,<3.0" +python-dateutil = ">=2.7.0,<3.0.0" +python-multipart = ">=0.0.5,<0.0.6" +sentinel = ">=0.3.0,<0.4.0" +typing_extensions = ">=3.7.4,<4.0.0" + +[package.extras] +asgi = ["starlette (>=0.13.6,<0.17.0)"] +debug-server = ["starlette (>=0.13.6,<0.17.0)", "uvicorn (>=0.11.6,<0.16.0)"] +django = ["django (>=2,<4)", "asgiref (>=3.2,<4.0)"] +flask = ["flask (>=1.1,<2.0)"] +opentelemetry = ["opentelemetry-api (<2)", "opentelemetry-sdk (<2)"] +pydantic = ["pydantic (<2)"] +sanic = ["sanic (>=20.12.2,<22.0.0)"] +aiohttp = ["aiohttp (>=3.7.4.post0,<4.0.0)"] +fastapi = ["fastapi (>=0.65.2)"] + +[[package]] +name = "strawberry-graphql-django" +version = "0.2.5" +description = "Strawberry GraphQL Django extension" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +Django = ">=3.0" +strawberry-graphql = ">=0.69.0" + [[package]] name = "toml" version = "0.10.2" @@ -383,7 +489,7 @@ python-versions = ">=3.6" name = "typing-extensions" version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -403,7 +509,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "0609fa501bc042ac6dcfec3238c9c75576730366189304e91091f20b1b7bf1e5" +content-hash = "0dd39131cb6b3158ec615ee0768e068463a26f566f875d70e47d3f0e620c999c" [metadata.files] asgiref = [ @@ -422,6 +528,10 @@ black = [ {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, ] +cached-property = [ + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, +] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, @@ -459,6 +569,10 @@ facebook-sdk = [ {file = "facebook_sdk-3.0.0-py2-none-any.whl", hash = "sha256:c94df84b2bba1c497684c169ed28a713b57917bf56f95fba4c2a5290c16ce81e"}, {file = "facebook_sdk-3.0.0-py3-none-any.whl", hash = "sha256:8ef0a0d2c98a515a926875bb4be9c9a4630a39fc8190bff8d5265d58af1ef257"}, ] +graphql-core = [ + {file = "graphql-core-3.1.6.tar.gz", hash = "sha256:e65975b6a13878f9113a1fa5320760585b522d139944e005936b1b8358d0651a"}, + {file = "graphql_core-3.1.6-py3-none-any.whl", hash = "sha256:c78d09596d347e1cffd266c5384abfedf43ed1eae08729773bebb3d527fe5a14"}, +] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, @@ -545,6 +659,10 @@ py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] +pygments = [ + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -553,6 +671,13 @@ pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +python-multipart = [ + {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, +] pytz = [ {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, @@ -599,14 +724,30 @@ requests = [ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, ] +sentinel = [ + {file = "sentinel-0.3.0-py3-none-any.whl", hash = "sha256:bd8710dd26752039c668604f6be2aaf741b56f7811c5924a4dcdfd74359244f3"}, + {file = "sentinel-0.3.0.tar.gz", hash = "sha256:f28143aa4716dbc8f6193f5682176a3c33cd26aaae05d9ecf66c186a9887cc2d"}, +] sentry-sdk = [ {file = "sentry-sdk-1.4.3.tar.gz", hash = "sha256:b9844751e40710e84a457c5bc29b21c383ccb2b63d76eeaad72f7f1c808c8828"}, {file = "sentry_sdk-1.4.3-py2.py3-none-any.whl", hash = "sha256:c091cc7115ff25fe3a0e410dbecd7a996f81a3f6137d2272daef32d6c3cfa6dc"}, ] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] sqlparse = [ {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, ] +strawberry-graphql = [ + {file = "strawberry-graphql-0.85.1.tar.gz", hash = "sha256:2707bed7ca8b784093b05ab345f4143453467acf21ee86a768a8dfb65d12d9ab"}, + {file = "strawberry_graphql-0.85.1-py3-none-any.whl", hash = "sha256:e92e4fb43beaa130cd3475b41d26fa913b7469cc624d5e53dba136c87fde7f43"}, +] +strawberry-graphql-django = [ + {file = "strawberry-graphql-django-0.2.5.tar.gz", hash = "sha256:483d97c24ce440a1e3cb92ec3e1fdc0cf534d9afa79600396b0a27a5d9d97793"}, + {file = "strawberry_graphql_django-0.2.5-py3-none-any.whl", hash = "sha256:dee8011bf074c618b7ddab0a92d0832b0ceea2dcb69ee422003a98e4a28c14d6"}, +] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, diff --git a/pyproject.toml b/pyproject.toml index 96f62a2..e7f260d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,8 @@ gunicorn = "20.1.0" mysqlclient = "2.0.3" Pillow = "8.4.0" sentry-sdk = "1.4.3" +strawberry-graphql = "^0.85.1" +strawberry-graphql-django = "^0.2.5" [tool.poetry.dev-dependencies] pytest = "^6.2.5"