Skip to content

Commit f222aa6

Browse files
authored
Merge pull request #56 from febus982/graphql_strawberry
Add example GraphQL endpoint
2 parents 7e1fca5 + c2a004b commit f222aa6

File tree

10 files changed

+231
-9
lines changed

10 files changed

+231
-9
lines changed

http_app/routes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from starlette.responses import HTMLResponse
44

55
from http_app.routes.api.books import router as api_books_router
6+
from http_app.routes.graphql import graphql_app
67
from http_app.routes.hello import router as hello_router
78
from http_app.routes.ping import router as ping_router
89

@@ -14,6 +15,7 @@ def init_versioned_routes(app: FastAPI) -> None:
1415
def init_unversioned_routes(app: FastAPI) -> None:
1516
app.include_router(ping_router)
1617
app.include_router(hello_router)
18+
app.include_router(graphql_app, prefix="/graphql")
1719

1820
@app.get("/docs", response_class=HTMLResponse, include_in_schema=False)
1921
async def get_api_versions() -> HTMLResponse:

http_app/routes/graphql/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from strawberry import Schema
2+
from strawberry.fastapi import GraphQLRouter
3+
4+
from .query import Query
5+
6+
schema = Schema(query=Query)
7+
8+
graphql_app: GraphQLRouter = GraphQLRouter(schema)

http_app/routes/graphql/query.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import List
2+
3+
import strawberry
4+
5+
from .resolvers import list_books
6+
from .types import Book
7+
8+
9+
@strawberry.type
10+
class Query:
11+
books: List[Book] = strawberry.field(resolver=list_books)

http_app/routes/graphql/resolvers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from domains.books import Book, BookService
2+
3+
4+
async def list_books():
5+
book_service = BookService()
6+
books = await book_service.list_books()
7+
return [Book(**x.dict()) for x in books]

http_app/routes/graphql/types.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from typing import Union
2+
3+
import strawberry
4+
5+
6+
@strawberry.type
7+
class Book:
8+
book_id: Union[int, None] = None
9+
title: str
10+
author_name: str

poetry.lock

Lines changed: 156 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ fastapi-versionizer = "^0.1.2"
3030
jinja2 = "^3.1.2"
3131
opentelemetry-instrumentation-fastapi = "*"
3232
starlette-prometheus = "^0.9.0"
33-
uvicorn = { version = "^0.22.0", extras = ["standard"] }
33+
strawberry-graphql = { version = "^0.193.0", extras = ["debug-server", "fastapi"] }
34+
uvicorn = { version = "^0.21.0", extras = ["standard"] }
3435

3536
[tool.poetry.group.grpc]
3637
optional = true
@@ -56,6 +57,7 @@ pytest-cov = "*"
5657
pytest-factoryboy = "*"
5758
pytest-xdist = "*"
5859
ruff = "*"
60+
strawberry-graphql = { version = "*", extras = ["debug-server", "fastapi"] }
5961

6062
[build-system]
6163
requires = ["poetry-core"]
@@ -78,7 +80,7 @@ files = [
7880
"di_container.py",
7981
"config.py",
8082
]
81-
plugins = "pydantic.mypy"
83+
plugins = "pydantic.mypy,strawberry.ext.mypy_plugin"
8284

8385
[[tool.mypy.overrides]]
8486
module = "grpc.aio.*"

tests/http_app/routes/books/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ def book_service() -> Iterator[MagicMock]:
1515
svc.create_book = AsyncMock(
1616
side_effect=lambda book: Book(book_id=randint(1, 1000), **book.dict())
1717
)
18+
svc.list_books = AsyncMock(
19+
return_value=[
20+
Book(
21+
book_id=123,
22+
title="The Shining",
23+
author_name="Stephen King",
24+
)
25+
]
26+
)
1827

1928
with patch("domains.books._service.BookService.__new__", return_value=svc):
2029
yield svc

tests/http_app/routes/books/graphql/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from fastapi import status
2+
from httpx import AsyncClient
3+
4+
5+
async def test_create_book(testapp):
6+
query = "{books{authorName, title, bookId}}"
7+
async with AsyncClient(app=testapp, base_url="http://test") as ac:
8+
response = await ac.post(
9+
"/graphql",
10+
json=dict(query=query),
11+
)
12+
assert response.status_code == status.HTTP_200_OK
13+
assert response.json() == {
14+
"data": {
15+
"books": [
16+
{"authorName": "Stephen King", "bookId": 123, "title": "The Shining"}
17+
]
18+
}
19+
}
20+
21+
"""
22+
Check new_book_data is a subset of response.json()["book"]
23+
(response.json()["book"] contains also the generated primary key)
24+
"""

0 commit comments

Comments
 (0)