go-kit-gqlgen-postgres-todo-example

command module
v0.0.0-...-64643be Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2022 License: Unlicense Imports: 13 Imported by: 0

README

==================================
Go GraphQL PostgreSQL Todo Example
==================================

.. image:: https://img.shields.io/badge/Language-Go-blue.svg
   :target: https://golang.org/

.. image:: https://godoc.org/github.com/siongui/go-kit-gqlgen-postgres-todo-example?status.svg
   :target: https://godoc.org/github.com/siongui/go-kit-gqlgen-postgres-todo-example

.. image:: https://github.com/siongui/go-kit-gqlgen-postgres-todo-example/workflows/ci/badge.svg
    :target: https://github.com/siongui/go-kit-gqlgen-postgres-todo-example/blob/master/.github/workflows/ci.yml

.. image:: https://goreportcard.com/badge/github.com/siongui/go-kit-gqlgen-postgres-todo-example
   :target: https://goreportcard.com/report/github.com/siongui/go-kit-gqlgen-postgres-todo-example

.. image:: https://img.shields.io/badge/license-Unlicense-blue.svg
   :target: https://github.com/siongui/go-kit-gqlgen-postgres-todo-example/blob/master/UNLICENSE


`Go kit`_ + GraphQL_ (gqlgen_) + PostgreSQL_ + gorm_ Todo example for Go_.

Development Environment:

  - `Ubuntu 20.04`_
  - `Go 1.17`_

.. contents:: Table of Contents


Usage
+++++

After git clone this repo, generate and run server:

.. code-block:: bash

  $ cd /path/to/this/repo/
  # go generate GraphQL code
  $ make schema_generate

See next section to run dockerized PostgreSQL. After PostgreSQL is running:

.. code-block:: bash

  # database migrations
  $ make database_migrations
  # Run server
  $ make

After the server is running, click on the link of log message. Now you can send
GraphQL requests via web interface.


Run Dockerized PostgreSQL
+++++++++++++++++++++++++

Install Docker_ and `Docker Compose`_

.. code-block:: bash

  $ cd /path/to/this/repo/
  $ docker-compose up

psql_ to connect to the database:

.. code-block:: bash

  # Default password: changeme. Can be changed in docker-compose.yml
  $ psql -h localhost -p 5432 -U postgres -d todo_db
  Password for user postgres:
  psql (12.9 (Ubuntu 12.9-0ubuntu0.20.04.1), server 14.1)
  WARNING: psql major version 12, server major version 14.
           Some psql features might not work.
  Type "help" for help.

  todo_db=#


GraphQL Example
+++++++++++++++

*getTodo* example #1:

.. code-block:: graphql

  {
    getTodo(id: "1") {
      id
      content_code
      created_date
      updated_date
      content_name
      description
      start_date
      end_date
      status
      created_by
      updated_by
    }
  }

*createTodo* example #1:

.. code-block:: graphql

  mutation {
    createTodo(
      input: {
        content_code: "TD001",
        content_name: "my name",
        description: "test",
        start_date: "2022-01-23T14:20:50.52+08:00",
        end_date: "2022-01-30T14:20:50.52+08:00",
        status: Active}
    ) {
      id
      content_code
      created_date
      updated_date
    }
  }

*createTodo* example #2:

.. code-block:: graphql

  mutation {
    createTodo(
      input: {
        content_code: "TD003",
        content_name: "my content name",
        description: "my content description",
        start_date: "2022-01-23T14:20:50.52+08:00",
        end_date: "2022-01-30T14:20:50.52+08:00",
        status: Active}
    ) {
      id
      content_code
      created_date
      updated_date
      content_name
      description
      start_date
      end_date
      status
      created_by
      updated_by
    }
  }

*TodoPages* example:

.. code-block:: graphql

  {
    TodoPages(paginationInput: {count: 5, page: 1}) {
      pagination_info {
        total_count
        total_pages
        current_page
      }
      todos {
        id
        content_code
        created_date
        updated_date
        content_name
        description
        start_date
        end_date
        status
        created_by
        updated_by
      }
    }
  }

*updateTodo* example #1:

.. code-block:: graphql

  mutation {
    updateTodo(
      id: "1000"
      input: {
        content_code: "TD0031",
        content_name: "my updated content name",
        description: "my updated content description",
        start_date: "2022-02-01T14:20:50.52+08:00",
        end_date: "2022-02-02T14:20:50.52+08:00",
        status: Inactive}
    ) {
      id
      content_code
      created_date
      updated_date
      content_name
      description
      start_date
      end_date
      status
      created_by
      updated_by
    }
  }

*updateTodo* example #2:

.. code-block:: graphql

  mutation {
    updateTodo(
      id: "5"
      input: {
        content_code: "TD007",
        content_name: "my updated content name2",
        description: "my updated content description7",
        status: Inactive}
    ) {
      id
      content_code
      created_date
      updated_date
      content_name
      description
      start_date
      end_date
      status
      created_by
      updated_by
    }
  }

*TodoSearch* example #1:

.. code-block:: graphql

  query {
    TodoSearch(
      paginationInput: {count: 5, page: 1}
      input:{
        content_code: "00"
      }
    ) {
      pagination_info {
        total_count
        total_pages
        current_page
      }
      todos {
        id
        content_code
        created_date
        updated_date
        content_name
        description
        start_date
        end_date
        status
        created_by
        updated_by
      }
    }
  }

*TodoSearch* example #2:

.. code-block:: graphql

  query {
    TodoSearch(
      paginationInput: {count: 5, page: 1}
      input:{
        start_date: "2022-02-06T07:11:18+08:00"
        status: Inactive
      }
    ) {
      pagination_info {
        total_count
        total_pages
        current_page
      }
      todos {
        id
        content_code
        created_date
        updated_date
        content_name
        description
        start_date
        end_date
        status
        created_by
        updated_by
      }
    }
  }


Linter
++++++

Two linters are used. graphql-schema-linter_ and golangci-lint_.

GraphQL Schema Linter
---------------------

Use graphql-schema-linter_ for GraphQL schema linting. See
`.graphql-schema-linterrc <.graphql-schema-linterrc>`_ for linting config.

To run the linter:

.. code-block:: bash

  $ make graphql_schema_lint

golangci-lint
-------------

Use golangci-lint_ for Go code linting. See
`.golangci.yml <.golangci.yml>`_ for linter config.

To install golangci-lint:

.. code-block:: bash

  $ make install_golangci_lint

To run golangci-lint:

.. code-block:: bash

  $ make golangci_lint


Database Migrations
+++++++++++++++++++

golang-migrate_ is used to apply database migrations.

To create migrations, install `golang-migrate CLI`_ first.

.. code-block:: bash

  $ cd /path/to/this/repo/
  $ migrate create -ext sql -dir migrations/ create_todo_table
  migrations/20220202204515_create_todo_table.up.sql
  migrations/20220202204515_create_todo_table.down.sql

Edit the ``up.sql`` and ``down.sql`` accordingly. After finish, set
**POSTGRESQL_URL** to tell migrate CLI where the database is:

.. code-block:: bash

  $ export POSTGRESQL_URL='postgres://postgres:changeme@localhost:5432/todo_db?sslmode=disable'

Now we apply the migrations to the database:

.. code-block:: bash

  $ migrate -database ${POSTGRESQL_URL} -path migrations/ up

Check if the migrations is correctly applied:

.. code-block:: bash

  # Default password: changeme. Can be changed in docker-compose.yml
  $ psql -h localhost -p 5432 -U postgres -d todo_db
  Password for user postgres:
  psql (12.9 (Ubuntu 12.9-0ubuntu0.20.04.1), server 14.1)
  WARNING: psql major version 12, server major version 14.
           Some psql features might not work.
  Type "help" for help.

  todo_db=# \dt+
                              List of relations
   Schema |       Name        | Type  |  Owner   |    Size    | Description
  --------+-------------------+-------+----------+------------+-------------
   public | schema_migrations | table | postgres | 8192 bytes |
   public | todos             | table | postgres | 8192 bytes |
  (2 rows)

  todo_db=# TABLE todos;
   id | content_code | created_at | updated_at | deleted_at | content_name | description | start_date | end_date | status | created_by | updated_by
  ----+--------------+------------+------------+------------+--------------+-------------+------------+----------+--------+------------+------------
  (0 rows)

Migrations with gorm.Model
--------------------------

gorm_ is ORM library for Go. The migration SQL for gorm.Model_:

.. code-block:: go

  // gorm.Model embedded in MyType
  type MyType struct {
  	gorm.Model
  }

The table name is *my_types*

.. code-block:: sql

  CREATE TABLE "my_types"
  (
      "id"         bigserial,
      "created_at" timestamptz NOT NULL,
      "updated_at" timestamptz NOT NULL,
      "deleted_at" timestamptz,
      PRIMARY KEY ("id")
  );

  CREATE INDEX "idx_my_type_deleted_at" ON "my_types" ("deleted_at")


Authentication and Permission
+++++++++++++++++++++++++++++

Steps to implement:

1. Get RSA Public key from http endpoint of identity provider.
2. Use gin or chi to to get the token from header, and passed the token to
   gqlgen resolver.
3. Verify and extract user info and permissons from the token.

- | `go - How to propagate context values from Gin middleware to gqlgen resolvers? - Stack Overflow <https://stackoverflow.com/questions/67267065/how-to-propagate-context-values-from-gin-middleware-to-gqlgen-resolvers>`_
  | `Providing authentication details through context — gqlgen <https://gqlgen.com/recipes/authentication/>`_
  | `Using Gin to setup HTTP handlers — gqlgen <https://gqlgen.com/recipes/gin/>`_

- `GitHub - ghiden/go-kit-stringsvc2-with-jwt: Go kit: stringsvc2 with JWT <https://github.com/ghiden/go-kit-stringsvc2-with-jwt>`_
- `Go-kit微服务| JWT身份认证 <https://liu-yt.github.io/2019/06/23/Go-kit%E5%BE%AE%E6%9C%8D%E5%8A%A1-JWT%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81/>`_
- `go-kit 微服务 身份认证 (JWT) | hwholiday <https://www.hwholiday.com/2020/go_kit_v3/>`_
- `go-kit authentication - Google search <https://www.google.com/search?q=go-kit+authentication>`_
- `Get HTTP headers in directives/mutations · Issue #262 · 99designs/gqlgen · GitHub <https://github.com/99designs/gqlgen/issues/262>`_
- `laisky-blog: [Golang] 使用 gqlgen 编写 GraphQL 后端 <https://blog.laisky.com/p/gqlgen/>`_
- `Using schema directives to implement permission checks — gqlgen <https://gqlgen.com/reference/directives/>`_
- `gqlgen data validation · GitHub <https://gist.github.com/david-yappeter/3b9c1d68588dc3e1fb4a4a6efc086d07>`_
- `Mapping GraphQL scalar types to Go types — gqlgen <https://gqlgen.com/reference/scalars/>`_
- `使用 GraphQL Gateway 串接多個 Data Schema - 小惡魔 - AppleBOY <https://blog.wu-boy.com/2021/02/graphql-gateway-in-golang/>`_
- `GraphQL with Golang: Building a GraphQL Server with GO and MySQL | by Vishal Jain | Towards Dev <https://towardsdev.com/graphql-with-golang-building-a-graphql-server-with-go-and-mysql-b931e8c3e3d3>`_
- `golang jwt parse rsa from url - Google search <https://www.google.com/search?q=golang+jwt+parse+rsa+from+url>`_


Code Structure
++++++++++++++

app config
----------

- `config/ <config/>`_: application configuration

GraphQL
-------

- `gqlgen.yml <gqlgen.yml>`_: gqlgen config file.
- `graph/ <graph/>`_: GraphQL schema, resolvers, and custom scalar.

business logic
--------------

- `todo/ <todo/>`_: Go micro service - *todo*
- `todo/tododb/ <todo/tododb/>`_: database library for *todo* service.

database migrations
-------------------

- `tools/migrate/ <tools/migrate/>`_: command line tool for database migrations.
- `migrations/ <migrations/>`_: database migrations SQL files.

dependency tracking
-------------------

- `tools/tools.go <tools/tools.go>`_: Track tool dependencies for a module.
  See [2]_


UNLICENSE
+++++++++

Released in public domain. See UNLICENSE_.


References
++++++++++

.. [1] `github.com/99designs/gqlgen <https://github.com/99designs/gqlgen>`_
.. [2] | `gqlgen Quick start <https://github.com/99designs/gqlgen#quick-start>`_
       | `How can I track tool dependencies for a module? <https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module>`_
.. [3] `github.com/siongui/go-kit-url-shortener-micro-service <https://github.com/siongui/go-kit-url-shortener-micro-service>`_
.. [4] `Building a GraphQL Server with Go Backend Tutorial | Getting Started <https://www.howtographql.com/graphql-go/1-getting-started/>`_
.. [5] `How To Remove Docker Images, Containers, and Volumes | DigitalOcean <https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes>`_
.. [6] | `go kit graphql <https://www.google.com/search?q=go+kit+graphql>`_
       | `GraphQL support · Issue #636 · go-kit/kit · GitHub <https://github.com/go-kit/kit/issues/636>`_
       | `Add initial GraphQL support by sagikazarmark · Pull Request #81 · sagikazarmark/modern-go-application · GitHub <https://github.com/sagikazarmark/modern-go-application/pull/81>`_
.. [7] `jinzhu/configor: Golang Configuration tool that support YAML, JSON, TOML, Shell Environment <https://github.com/jinzhu/configor>`_
.. [8] generating core failed: comment the ``autobind`` in https://gqlgen.com/config.
       See `generating core failed: unable to load example/graph/model in v0.16 <https://github.com/99designs/gqlgen/issues/1860>`_
.. [9] | `golang migrate err no change - Google search <https://www.google.com/search?q=golang+migrate+err+no+change>`_
       | `go - golang-migrate no change error on initial migration - Stack Overflow <https://stackoverflow.com/questions/67910574/golang-migrate-no-change-error-on-initial-migration>`_
       | `Migrate.Up() errors out if the latest schema is in use · Issue #100 · golang-migrate/migrate · GitHub <https://github.com/golang-migrate/migrate/issues/100>`_
.. [10] | `Using Gin to setup HTTP handlers — gqlgen <https://gqlgen.com/recipes/gin/>`_
        | `How can i use gin with standard handlers? · Issue #57 · gin-gonic/gin · GitHub <https://github.com/gin-gonic/gin/issues/57>`_
        | `Using http.Handler? · Issue #293 · gin-gonic/gin · GitHub <https://github.com/gin-gonic/gin/issues/293>`_


.. _Go: https://golang.org/
.. _Go kit: https://gokit.io/
.. _GraphQL: https://graphql.org/
.. _gqlgen: https://github.com/99designs/gqlgen
.. _PostgreSQL: https://www.postgresql.org/
.. _Ubuntu 20.04: https://releases.ubuntu.com/20.04/
.. _Go 1.17: https://golang.org/dl/
.. _Docker: https://docs.docker.com/engine/install/
.. _Docker Compose: https://docs.docker.com/compose/install/
.. _psql: https://www.postgresguide.com/utilities/psql/
.. _graphql-schema-linter: https://github.com/cjoudrey/graphql-schema-linter
.. _golangci-lint: https://golangci-lint.run/
.. _golang-migrate: https://github.com/golang-migrate/migrate
.. _golang-migrate CLI: https://github.com/golang-migrate/migrate/tree/master/cmd/migrate
.. _gorm: https://gorm.io/
.. _gorm.Model: https://gorm.io/docs/models.html#gorm-Model
.. _UNLICENSE: https://unlicense.org/

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
tools

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL