Skip to content

Commit

Permalink
feat: add GraphQL API implementation using django-graphene (#449)
Browse files Browse the repository at this point in the history
> Are there any side effects?
None

---------

Co-authored-by: Saurabh Kumar <[email protected]>
Co-authored-by: Sanyam Khurana <[email protected]>
Co-authored-by: sahithchandan <[email protected]>
  • Loading branch information
4 people authored Mar 28, 2023
1 parent 56334b6 commit 7295330
Show file tree
Hide file tree
Showing 35 changed files with 1,322 additions and 44 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- Postgis Setup
- Newrelic
- Sentry
- [GraphQL](https://graphql.org/) support via [Graphene-Django](https://docs.graphene-python.org/projects/django/en/latest/) (Optional)
- pre-commit hooks


Expand Down
4 changes: 4 additions & 0 deletions cookiecutter-test-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default_context:
enable_whitenoise: "y"
add_celery: "y"
add_graphql: "y"
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
, "add_sentry": "y"
, "add_django_auth_wall": "y"
, "add_celery": "n"
, "add_graphql": "n"
, "add_pre_commit": "y"
, "add_docker": "y"
, "pagination": ["LimitOffsetPagination", "CursorPagination"]
Expand Down
6 changes: 6 additions & 0 deletions hooks/post_gen_project.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ if echo "{{ cookiecutter.add_docker }}" | grep -iq "^n"; then
rm -rf .envs compose local.yml dev.yml docs/backend/docker_setup.md
fi

if echo "{{ cookiecutter.add_graphql }}" | grep -iq "^n"; then
rm -rf {{ cookiecutter.main_module }}/graphql
rm -rm {{ cookiecutter.main_module }}/docs/graphql
rm -rf tests/graphql
fi

if echo "$yn" | grep -iq "^y"; then
echo "==> Checking system dependencies. You may need to enter your sudo password."

Expand Down
2 changes: 1 addition & 1 deletion run_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fi
rm -rf hello-world-backend/;

# Generate new code, (it also creates db, migrate and install dependencies)
yes 'y' | cookiecutter . --no-input
yes 'y' | cookiecutter . --no-input --config-file cookiecutter-test-config.yaml

# Run the tests present inside generate project
cd hello-world-backend;
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.github_repository}}/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# DJANGO_AWS_S3_HOST=''
# DJANGO_AWS_S3_REGION_NAME=''

# Django Rest Framework
# APIs
# ==============================
# API_DEBUG=False

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG PYTHON_VERSION=3.9-slim-buster
# define an alias for the specfic python version used in this file.
FROM python:${PYTHON_VERSION} as python

ENV POETRY_VERSION=1.2.0
ENV POETRY_VERSION=1.3.2

ARG BUILD_ENVIRONMENT=dev
ARG APP_HOME=/app
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ FROM python:${PYTHON_VERSION} as python
ARG BUILD_ENVIRONMENT=local
ARG APP_HOME=/app

ENV POETRY_VERSION=1.2.0
ENV POETRY_VERSION=1.3.2
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV BUILD_ENV ${BUILD_ENVIRONMENT}
Expand Down
64 changes: 64 additions & 0 deletions {{cookiecutter.github_repository}}/docs/graphql/0-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# GraphQL

## Authentication

For all auth related requests (`login`, `register` etc), clients need to refer to [docs mentioned here](1-auth.md).
For clients to make authenticated requests, the `auth_token` value (received from the `login` endpoint) should be included in the `Authorization` HTTP header. The value should be prefixed by the string literal `Bearer`, with whitespace separating the two strings.

## API Endpoint

```
POST /graphql
```

All the queries and mutations will be a POST request to the above endpoint. We've documented a sample header and payload to be sent with the request.

__Headers__

```json
{
"Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2F1dGhlbnRpY2F0aW9uX2lkIjoiNzY1MjE3YTgtNzU5OS00ZTI1LTljMjQtYjdjOTJlODc4MjAxIn0.972Irua8Ql0NRf_KxgYI7q1imPBkf2XJG25L94JM8Hw"
}
```

__Payload__

```json
{
"query": "query MyInfo { me { id firstName lastName email } }",
"variables":null,
"operationName":"MyInfo"
}
```

## Pagination

Pagination is required in most queries that return lists of items in the GraphQL API. It limits the number of results returned by the server to a more manageable size and avoids data flow disruptions.

There are two types of lists in GraphQL:

- `[Foo]` is a simple list. It is used to query a list containing several items. An excellent example of a simple list could be a query for product variants which returns a list with a manageable number of results.
- `FooConnection` represents a more complex list. When queried, it will return an unknown or large number of results.

Pagination is used to help you handle large amounts of items returned by the connection list type.

The pagination model is based on the [GraphQL Connection Specification](https://relay.dev/graphql/connections.htm). Its schema looks like this:

```
type FooConnection {
pageInfo: PageInfo!
edges: [FooEdge!]!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type FooEdge {
node: Foo!
cursor: String!
}
```
144 changes: 144 additions & 0 deletions {{cookiecutter.github_repository}}/docs/graphql/1-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Authentication

!!!info
For API overview and usages, check out [this page](0-overview.md).


## Register

__Request__
```
mutation {
signup (
input: {
email: "[email protected]",
firstName: "a",
lastName: "b",
password: "password"
}
) {
user {
id
email
}
}
}
```

__Response__
```json
{
"data": {
"signup": {
"user": {
"id": "f1b234c8-8bdf-4a33-bfae-a1929c2e8ca0",
"email": "[email protected]"
}
}
}
}
```


## Login
__Request__
```
mutation {
login (
input: {
email: "[email protected]",
password: "password"
}
) {
user {
id, email, firstName, lastName, authToken
}
}
}
```

__Response__

```json
{
"data": {
"login": {
"user": {
"id": "f1b234c8-8bdf-4a33-bfae-a1929c2e8ca0",
"email": "[email protected]",
"firstName": "Dave",
"lastName": "",
"authToken": "eyJhbGciO..."
}
}
}
}
```


## Request Password Reset

__Request__
```
mutation RequestPasswordReset {
passwordReset (
input: {
email: "[email protected]"
}
) {
message
}
}
```

__Response__

```json
{
"data": {
"passwordReset": {
"message": "Further instructions will be sent to the email if it exists"
}
}
}
```


## Password Change
(requires authentication)

__Request__
```
mutation PasswordChange {
passwordChange (
input: {
currentPassword: "password", newPassword:"newpassword"
}
) {
user {
email
firstName
lastName
authToken
}
}
}
```

__Response__

```json
{
"data": {
"login": {
"user": {
"id": "f1b234c8-8bdf-4a33-bfae-a1929c2e8ca0",
"email": "[email protected]",
"firstName": "Dave",
"lastName": "",
"authToken": "eyJhbGciO..."
}
}
}
}
```
79 changes: 79 additions & 0 deletions {{cookiecutter.github_repository}}/docs/graphql/2-users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## Current User
(requires authentication)

__Request__
```
query {
me {
id
firstName
lastName
email
}
}
```

__Response__

```json
{
"data": {
"me": {
"id": "Q3VycmVudFVzZXI6M2MzYjVhMmUtMWM0MC00MTQzLTk1N2ItYjVlYTAzOWU0NzVi",
"first_name": "John",
"last_name": "Hawley",
"email": "[email protected]"
}
}
}
```


## All Users
(requires authentication and superuser privilege)

__Request__
```
query {
users {
totalCount,
edgeCount,
edges {
node {
id,
firstName,
lastName
}
}
}
}
```

__Response__

```json
{
"data": {
"users": {
"totalCount": 2,
"edgeCount": 2,
"edges": [
{
"node": {
"id": "VXNlckNvbm5lY3Rpb246M2MzYjVhMmUtMWM0MC00MTQzLTk1N2ItYjVlYTAzOWU0NzVi",
"firstName": "first name",
"lastName": "last name"
}
},
{
"node": {
"id": "VXNlckNvbm5lY3Rpb246ZjU4N2IyY2EtNThmMS00NTE3LTgyMTEtYzczODA3YTI1ZTU1",
"firstName": "fueled",
"lastName": "user"
}
}
]
}
}
}
```
27 changes: 27 additions & 0 deletions {{cookiecutter.github_repository}}/docs/graphql/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Errors

## Generic Errors


For `/graphql` requests, the API will return the error in the following format:

```json
{
"errors": [
{
"message": "You do not have permission to perform this action",
"locations": [
{
"line": 33,
"column": 3
}
],
"path": [
"users"
]
}
]
}
```

__NOTE__: The copy for most of these error messages can be changed by backend developers.
Loading

0 comments on commit 7295330

Please sign in to comment.