
- - Indie Stack - -
-- Check the README.md file for instructions on how to get this - project deployed. -
-diff --git a/.codeclimate.yml b/.codeclimate.yml index a3b960126ff8c9d340f14e6ce4906527f4fad133..1a58b3ee0697e764ca8e089cab3f94f2161f59fe 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,12 +1,6 @@ --- version: "2" plugins: - govet: - enabled: true - sonar-php: - enabled: true - sonar-python: - enabled: true csslint: enabled: true coffeelint: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f68dd78a35e02d4e91a14e078d0a4847788d6463..21cbb611ab11de6a31a21a15932249bdfaf82041 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,29 +4,16 @@ workflow: - if: $CI_COMMIT_TAG - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH -stages: [test, qa, release] +stages: [test, release] include: - - local: 'ci/.gitlab-ci-golang.yml' - - local: 'ci/.gitlab-ci-node.yml' - - local: 'ci/.gitlab-ci-python.yml' - - local: 'ci/.gitlab-ci-php.yml' - - local: 'ci/.gitlab-ci-ruby.yml' - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/code-quality@$CI_COMMIT_SHA inputs: - stage: qa - debug: "1" + stage: test -# We customize the `code_quality` job to enable verbose logs (for debugging), and to also save the -# code quality report so it can be inspected by other jobs to verify it works correctly. code_quality: - artifacts: - paths: - - gl-code-quality-report.json rules: - if: $CI_MERGE_REQUEST_ID || $CI_COMMIT_TAG || $CI_COMMIT_BRANCH - tags: - - saas-linux-medium-amd64 ensure-job-added: stage: test diff --git a/ci/.gitlab-ci-golang.yml b/ci/.gitlab-ci-golang.yml deleted file mode 100644 index 57f91f61aa2119a568a48e8b520c7e9a43686408..0000000000000000000000000000000000000000 --- a/ci/.gitlab-ci-golang.yml +++ /dev/null @@ -1,30 +0,0 @@ -run-golang-test: - image: golang:latest - stage: test - variables: - GO_ENV: test - before_script: - - go version # Print out golang version for debugging - - apt-get update - - apt-get install sqlite3 - - mkdir -p $GOPATH/src/gitlab.com/test-code-quality-ci-component/sample-golang-echo-app - - mv $CI_PROJECT_DIR/src/sample-golang-echo-app/* $GOPATH/src/gitlab.com/test-code-quality-ci-component/sample-golang-echo-app - - cd $GOPATH/src/gitlab.com/test-code-quality-ci-component/sample-golang-echo-app - - go install github.com/ybkuroki/go-webapp-sample@latest - - go mod download - - export PATH="$PATH:$GOPATH/bin" - script: - - go test -v ./... - -verify-golang-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 govet offense" - - | - count=`jq 'map(select(.engine_name=="govet")) | length' gl-code-quality-report.json` - if [ "$count" == "0" ]; then - exit 1 - fi diff --git a/ci/.gitlab-ci-node.yml b/ci/.gitlab-ci-node.yml deleted file mode 100644 index 1d440856d674238e03451dfcd5e1cfb7bc53e06c..0000000000000000000000000000000000000000 --- a/ci/.gitlab-ci-node.yml +++ /dev/null @@ -1,27 +0,0 @@ -run-node-test: - image: node:latest - stage: test - cache: - paths: - - node_modules/ - before_script: - - node -v # Print out node version for debugging - - cd src/sample-node-remix-app - - npm install - script: - - npm run test - -verify-node-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 eslint, 1 structure and 1 duplication findings" - - | - eslint_count=`jq 'map(select(.engine_name=="eslint")) | length' gl-code-quality-report.json` - structure_count=`jq 'map(select(.engine_name=="structure")) | length' gl-code-quality-report.json` - duplication_count=`jq 'map(select(.engine_name=="duplication")) | length' gl-code-quality-report.json` - if [ "$eslint_count" == "0" ] || [ "$structure_count" == "0" ] || [ "$duplication_count" == "0" ]; then - exit 1 - fi diff --git a/ci/.gitlab-ci-php.yml b/ci/.gitlab-ci-php.yml deleted file mode 100644 index 0cc46cf08a4c6d1704694eeac33d696826a4a456..0000000000000000000000000000000000000000 --- a/ci/.gitlab-ci-php.yml +++ /dev/null @@ -1,41 +0,0 @@ -run-php-laravel-test: - image: php:8.2-cli - stage: test - services: - - mysql:latest - variables: - MYSQL_DATABASE: php_laravel_app - MYSQL_ROOT_PASSWORD: secret - DB_HOST: mysql - DB_USERNAME: root - cache: - paths: - - vendor/ - before_script: - - php -v # Print out php version for debugging - - cd src/sample-php-laravel-app - - cp .env.example .env - - apt-get update - - apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev libzip-dev - - apt-get clean - - docker-php-ext-install pdo_mysql zip - - curl --silent --show-error "https://getcomposer.org/installer" | php -- --install-dir=/usr/local/bin --filename=composer - - composer install - - php artisan key:generate - - php artisan migrate - script: - - vendor/bin/phpunit - -verify-php-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 sonar-php offense" - - | - count=`jq 'map(select(.engine_name=="sonar-php")) | length' gl-code-quality-report.json` - if [ "$count" == "0" ]; then - exit 1 - fi - diff --git a/ci/.gitlab-ci-python.yml b/ci/.gitlab-ci-python.yml deleted file mode 100644 index f71a5bacf505bc3e0d76d0266c1bd8bd828ef201..0000000000000000000000000000000000000000 --- a/ci/.gitlab-ci-python.yml +++ /dev/null @@ -1,41 +0,0 @@ -run-python-test: - image: ubuntu:20.04 - stage: test - services: - - mysql:latest - variables: - MYSQL_DATABASE: python_django_app - MYSQL_ROOT_PASSWORD: secret - cache: - paths: - - ~/.cache/pip/ - before_script: - - cd src/sample-python-django-app - - apt -y update - - apt -y install apt-utils - - DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata - - apt -y install net-tools python3.8 python3-pip python3-venv mysql-client libmysqlclient-dev pkg-config - - apt -y upgrade - - python3 -m venv env - - source env/bin/activate - - env/bin/python -V # Print out python version for debugging - - env/bin/pip install Django mysqlclient - - env/bin/pip freeze > requirements.txt - - env/bin/pip install -r requirements.txt - script: - # The MYSQL user only gets permissions for MYSQL_DB, so Django can't create a test database. - - echo "GRANT ALL on *.* to 'root';"| mysql -u root --password="secret" -h mysql - - env/bin/python manage.py test - -verify-python-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 sonar-python finding" - - | - count=`jq 'map(select(.engine_name=="sonar-python")) | length' gl-code-quality-report.json` - if [ "$count" == "0" ]; then - exit 1 - fi diff --git a/ci/.gitlab-ci-ruby.yml b/ci/.gitlab-ci-ruby.yml deleted file mode 100644 index 1f52e20bc78768097e6f1e023bbac6ee29b7b2e3..0000000000000000000000000000000000000000 --- a/ci/.gitlab-ci-ruby.yml +++ /dev/null @@ -1,55 +0,0 @@ -run-ruby-rails-test: - image: ruby:3.2.2 - stage: test - cache: - paths: - - vendor/ruby - before_script: - - ruby -v # Print out ruby version for debugging - - apt-get update -q && apt-get install nodejs -yqq - - cd src/sample-ruby-rails-app - - bundle lock --add-platform aarch64-linux - - bundle config set --local deployment true - - bundle install -j $(nproc) - script: - - bin/rails test - -run-ruby-gem-test: - image: ruby:latest - stage: test - cache: - paths: - - vendor/ruby - before_script: - - ruby -v # Print out ruby version for debugging - - apt-get update -q && apt-get install nodejs -yqq - - cd src/sample-ruby-gem - - bin/setup - script: - - rake spec - -verify-ruby-rails-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 rubocop offense" - - | - count=`jq 'map(select(.engine_name=="rubocop")) | length' gl-code-quality-report.json` - if [ "$count" == "0" ]; then - exit 1 - fi - -verify-ruby-gem-findings: - image: badouralix/curl-jq - stage: qa - needs: - - code_quality - script: - - echo "Expect code_quality job will have at least 1 fixme offense" - - | - count=`jq 'map(select(.engine_name=="fixme")) | length' gl-code-quality-report.json` - if [ "$count" == "0" ]; then - exit 1 - fi diff --git a/src/sample-golang-echo-app/.github/.golangci.yml b/src/sample-golang-echo-app/.github/.golangci.yml deleted file mode 100644 index 1801df17a56c40168a995a83ade291cc02401cec..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/.golangci.yml +++ /dev/null @@ -1,112 +0,0 @@ -# ref: https://github.com/golangci/golangci-lint/blob/master/.golangci.yml -# all available settings of specific linters -run: - concurrency: 4 - timeout: 3m - -linters-settings: - dupl: - threshold: 150 - funlen: - lines: 100 - statements: 50 - goconst: - min-len: 3 - min-occurrences: 2 - gocyclo: - min-complexity: 15 - gomnd: - # don't include the "operation" and "assign" - checks: - - argument - - case - - condition - - return - gofmt: - simplify: true - govet: - check-shadowing: true - settings: - printf: - funcs: - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - lll: - line-length: 120 - misspell: - locale: US - nakedret: - max-func-lines: 20 - revive: - ignore-generated-header: true - severity: warning - confidence: 0.8 - errorCode: 0 - warningCode: 0 - rules: - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: exported - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id - -linters: - disable-all: true - enable: - # default - # ref: https://golangci-lint.run/usage/linters/ - #- deadcode - #- errcheck - #- gosimple - #- govet - #- ineffassign - #- staticcheck - #- structcheck - #- typecheck - #- unused - #- varcheck - # add - - dupl - - errcheck - - funlen - - goconst - - gocyclo - - gofmt - - goimports - - gomnd - - govet - - lll - - misspell - - nakedret - - staticcheck - - stylecheck - - typecheck - - unconvert - - unparam - - revive - -# https://github.com/golangci/golangci/wiki/Configuration -# latest version: https://github.com/golangci/golangci-lint -service: - golangci-lint-version: 1.51.2 diff --git a/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/bug_report.md b/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 69fdb0114fb2486202c35747fc44933a9d8c8097..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "[BUG]" -labels: bug -assignees: '' - ---- - -## Summary -> Write the actual behavior and the purpose to modify. - -## Cause -> Why such a problem happened? - -### To reproduce -Perform the follwing steps to reproduce the problem. - -1. … -1. … - -## Expected behavior -Expected the follwing behavior. - -## How to deal with this issue -> How do you fix it? - -## Notes diff --git a/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/feature_request.md b/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 792495bd321d790c0e51d3db5910b880ace2820e..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "[NEW]" -labels: enhancement -assignees: '' - ---- - -## Purpose -> What is it necessary for? - -## Expected behavior -Expected the follwing behavior. - -## How to deal with this issue -> How do you fix it? - -## Notes diff --git a/src/sample-golang-echo-app/.github/dependabot.yml b/src/sample-golang-echo-app/.github/dependabot.yml deleted file mode 100644 index 459b7f171be80c94fca88316cce224f4c29bee90..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 -updates: - - package-ecosystem: gomod - directory: "/" - schedule: - interval: daily - - package-ecosystem: github-actions - directory: "/" - schedule: - interval: daily \ No newline at end of file diff --git a/src/sample-golang-echo-app/.github/pull_request_template.md b/src/sample-golang-echo-app/.github/pull_request_template.md deleted file mode 100644 index 151065d3cbd33b63160c50a23313162c64b289dc..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/pull_request_template.md +++ /dev/null @@ -1,9 +0,0 @@ -### Fixes #[ISSUE NUMBER]. - -Changes proposed in this pull request: - -- ... -- ... -- ... - -by [YOUR NAME] diff --git a/src/sample-golang-echo-app/.github/workflows/check.yml b/src/sample-golang-echo-app/.github/workflows/check.yml deleted file mode 100644 index e279b3bc2ece13efe65bb346a6b606e52960fd25..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/workflows/check.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: check - -on: - pull_request: - branches: [ master ] - -jobs: - check: - name: check - runs-on: ubuntu-latest - steps: - # Set up GOPATH - - name: set up - uses: actions/setup-go@v4 - with: - go-version: '1.20' - id: go - # Check out this repository - - name: checkout - uses: actions/checkout@v3 - # Store cache - - name: cache - uses: actions/cache@v3.3.1 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - # Run golangci-lint using reviewdog - - name: golangci-lint - uses: reviewdog/action-golangci-lint@v2 - with: - github_token: ${{ secrets.github_token }} - level: warning - golangci_lint_flags: "--config=.github/.golangci.yml" - reporter: github-pr-review - # Run test - - name: test - run: go test -cover ./... diff --git a/src/sample-golang-echo-app/.github/workflows/release.yml b/src/sample-golang-echo-app/.github/workflows/release.yml deleted file mode 100644 index 926252c68a5d111700e9a429bc6eb99f2ed7fbff..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.github/workflows/release.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: release -on: - push: - tags: - - "v[0-9]+.[0-9]+.[0-9]+" -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: '1.20' - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v4.2.0 - with: - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/sample-golang-echo-app/.gitignore b/src/sample-golang-echo-app/.gitignore deleted file mode 100644 index b851cf98aa22b7c816fc82f6891d9b3d6f2342a2..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib -*.db - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -#vendor/ - -# Output file of the swaggo/swag -swagger.json -swagger.yaml - -# Debug folder -.vscode diff --git a/src/sample-golang-echo-app/.goreleaser.yml b/src/sample-golang-echo-app/.goreleaser.yml deleted file mode 100644 index 5269a1a9f993b78f88800069590d9e6d5699ce15..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/.goreleaser.yml +++ /dev/null @@ -1,52 +0,0 @@ -# This is an example .goreleaser.yml file with some sensible defaults. -# Make sure to check the documentation at https://goreleaser.com -project_name: go-webapp-sample -env: - - GO111MODULE=on -before: - hooks: - # You may remove this if you don't use go modules. - - go mod tidy -builds: - - main: . - binary: go-webapp-sample - ldflags: - - -s -w - - -X main.Version={{.Version}} - - -X main.Revision={{.ShortCommit}} - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - -archives: - - format: tar.gz - # this name template makes the OS and Arch compatible with the results of uname. - name_template: >- - {{ .ProjectName }}_ - {{- title .Os }}_ - {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - # use zip for windows archives - format_overrides: - - goos: windows - format: zip -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ incpatch .Version }}-next" -changelog: - filters: - exclude: - - polish - - bump - - typo - -# The lines beneath this are called `modelines`. See `:help modeline` -# Feel free to remove those if you don't want/use them. -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json -# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/src/sample-golang-echo-app/CONTRIBUTING.md b/src/sample-golang-echo-app/CONTRIBUTING.md deleted file mode 100644 index 88ab1cc1baab39cdb4ac598ac651c4cd6b05ee49..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/CONTRIBUTING.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contribution -## Preface -Thank you for considering to contribute to this sample application. -I have created this sample application to be helpful as possible whenever you choose to develop a web application using golang. - -## How to report a bug -Please create an issue which highlights the following points when you report a bug: - -1. Version of golang you are using. -1. Operating system you are using. -1. Reproduce the bug. -1. Expected behavior (if any). - -Also, please write about it when you know the causes and how to fix the bug. - -1. Cause -1. How to fix - -## How to suggest a feature or enhancement -Please create an issue which highlights the purpose (feature or enhancement) and expected behavior, and also the functions which you would like to implement as a sample. - -1. Purpose. -1. Expected behavoir (if any), What kind of function do you propose? -1. How to develop - -## How to create a pull request -You can feel free to fork this repository, fix the source code and create a pull request when you are certain that you can resolve an issue. -And after that, please check passed the check workflow of GitHub Action. - -I will check your pull request, and I may suggest some improvements or alternatives. -If there was no problem, I will merge your changes. diff --git a/src/sample-golang-echo-app/LICENSE b/src/sample-golang-echo-app/LICENSE deleted file mode 100644 index 5b3af9864081c3a41ce6cbf8553cff2495e92660..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Yuta Kuroki - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/sample-golang-echo-app/README.md b/src/sample-golang-echo-app/README.md deleted file mode 100644 index 68b95b1e8f36f4357f941ab3a4f109e4e969b636..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/README.md +++ /dev/null @@ -1,182 +0,0 @@ -# go-webapp-sample - -[](https://github.com/ybkuroki/go-webapp-sample/blob/master/LICENSE) -[](https://goreportcard.com/report/github.com/ybkuroki/go-webapp-sample) -[](https://github.com/ybkuroki/go-webapp-sample/actions?query=workflow%3Acheck) -[](https://github.com/ybkuroki/go-webapp-sample/releases) - -## Preface -This repository is the sample of web application using golang. -This sample uses [Echo](https://echo.labstack.com/) as web application framework, [Gorm](https://gorm.io/) as OR mapper and [Zap logger](https://pkg.go.dev/go.uber.org/zap) as logger. -This sample application provides only several functions as Web APIs. -Please refer to the 'Service' section about the detail of those functions. - -Also, this application contains the static contents such as html file, css file and javascript file which built [vuejs-webapp-sample](https://github.com/ybkuroki/vuejs-webapp-sample) project to easily check the behavior of those functions. -So, you can check this application without starting a web server for front end. -Please refer to the 'Starting Server' section about checking the behavior of this application. - -If you would like to develop a web application using golang, please feel free to use this sample. - -## Install -Perform the following steps: -1. Download(`x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z`) and install [MinGW(gcc)](https://sourceforge.net/projects/mingw-w64/files/?source=navbar). -1. Download and install [Visual Studio Code(VS Code)](https://code.visualstudio.com/). -1. Download and install [Golang](https://golang.org/). -1. Get the source code of this repository by the following command. - ```bash - go install github.com/ybkuroki/go-webapp-sample@latest - ``` - -## Starting Server -There are 2 methods for starting server. - -### Without Web Server -1. Starting this web application by the following command. - ```bash - go run main.go - ``` -1. When startup is complete, the console shows the following message: - ``` - http server started on [::]:8080 - ``` -1. Access [http://localhost:8080](http://localhost:8080) in your browser. -1. Login with the following username and password. - - username : ``test`` - - password : ``test`` - -### With Web Server -#### Starting Application Server -1. Starting this web application by the following command. - ```bash - go run main.go - ``` -1. When startup is complete, the console shows the following message: - ``` - http server started on [::]:8080 - ``` -1. Access [http://localhost:8080/api/health](http://localhost:8080/api/health) in your browser and confirm that this application has started. - ``` - healthy - ``` -#### Starting Web Server -1. Clone [vuejs-webapp-sample](https://github.com/ybkuroki/vuejs-webapp-sample) project and install some tools. -1. Start by the following command. - ```bash - npm run serve - ``` -1. When startup is complete, the console shows the following message: - ``` - DONE Compiled successfully in *****ms - - App running at: - - Local: http://localhost:3000/ - - Network: http://192.168.***.***:3000/ - - Note that the development build is not optimized. - To create a production build, run npm run build. - ``` -1. Access [http://localhost:3000](http://localhost:3000) in your browser. -1. Login with the following username and password. - - username : ``test`` - - password : ``test`` - -## Using Swagger -In this sample, Swagger is enabled only when executed this application on the development environment. -Swagger isn't enabled on the another environments in default. - -### Accessing to Swagger -1. Start this application according to the 'Starting Application Server' section. -2. Access [http://localhost:8080/swagger/index.html](http://localhost:8080/swagger/index.html) in your browser. - -### Updating the existing Swagger document -1. Update some comments of some controllers. -2. Download Swag library. (Only first time) - ```bash - go install github.com/swaggo/swag/cmd/swag@latest - ``` -3. Update ``docs/docs.go``. - ```bash - swag init - ``` - -## Build executable file -Build this source code by the following command. -```bash -go build main.go -``` - -## Project Map -The following figure is the map of this sample project. - -``` -- go-webapp-sample - + config … Define configurations of this system. - + logger … Provide loggers. - + middleware … Define custom middleware. - + migration … Provide database migration service for development. - + router … Define routing. - + controller … Define controllers. - + model … Define models. - + repository … Provide a service of database access. - + service … Provide a service of book management. - + session … Provide session management. - + test … for unit test - - main.go … Entry Point. -``` - -## Services -This sample provides 3 services: book management, account management, and master management. -Regarding the detail of the API specification, please refer to the 'Using Swagger' section. - -### Book Management -There are the following services in the book management. - -|Service Name|HTTP Method|URL|Parameter|Summary| -|:---|:---:|:---|:---|:---| -|Get Service|GET|``/api/books/[BOOK_ID]``|Book ID|Get a book data.| -|List/Search Service|GET|``/api/books?query=[KEYWORD]&page=[PAGE_NUMBER]&size=[PAGE_SIZE]``|Page, Keyword(Optional)|Get a list of books.| -|Regist Service|POST|``/api/books``|Book|Regist a book data.| -|Edit Service|PUT|``/api/books``|Book|Edit a book data.| -|Delete Service|DELETE|``/api/books``|Book|Delete a book data.| - -### Account Management -There are the following services in the Account management. - -|Service Name|HTTP Method|URL|Parameter|Summary| -|:---|:---:|:---|:---|:---| -|Login Service|POST|``/api/auth/login``|Session ID, User Name, Password|Session authentication with username and password.| -|Logout Service|POST|``/api/auth/logout``|Session ID|Logout a user.| -|Login Status Check Service|GET|``/api/auth/loginStatus``|Session ID|Check if the user is logged in.| -|Login Username Service|GET|``/api/auth/loginAccount``|Session ID|Get the login user's username.| - -### Master Management -There are the following services in the Master management. - -|Service Name|HTTP Method|URL|Parameter|Summary| -|:---|:---:|:---|:---|:---| -|Category List Service|GET|``/api/categories``|Nothing|Get a list of categories.| -|Format List Service|GET|``/api/formats``|Nothing|Get a list of formats.| - -## Tests -Create the unit tests only for the packages such as controller, service, model/dto and util. The test cases is included the regular cases and irregular cases. Please refer to the source code in each packages for more detail. - -The command for testing is the following: -```bash -go test ./... -v -``` - -## Libraries -This sample uses the following libraries. - -|Library Name|Version| -|:---|:---:| -|echo|4.10.2| -|gorm|1.24.6| -|go-playground/validator.v9|9.31.0| -|zap|1.24.0| - -## Contribution -Please read [CONTRIBUTING.md](https://github.com/ybkuroki/go-webapp-sample/blob/master/CONTRIBUTING.md) for proposing new functions, reporting bugs and submitting pull requests before contributing to this repository. - -## License -The License of this sample is *MIT License*. diff --git a/src/sample-golang-echo-app/config/config.go b/src/sample-golang-echo-app/config/config.go deleted file mode 100644 index afee25ef6a4cc628ae7b5284bfeccf9c094165f9..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/config/config.go +++ /dev/null @@ -1,95 +0,0 @@ -package config - -import ( - "embed" - "flag" - "fmt" - "os" - - "github.com/ybkuroki/go-webapp-sample/util" - "gopkg.in/yaml.v3" -) - -// Config represents the composition of yml settings. -type Config struct { - Database struct { - Dialect string `default:"sqlite3"` - Host string `default:"book.db"` - Port string - Dbname string - Username string - Password string - Migration bool `default:"false"` - } - Redis struct { - Enabled bool `default:"false"` - ConnectionPoolSize int `yaml:"connection_pool_size" default:"10"` - Host string - Port string - } - Extension struct { - MasterGenerator bool `yaml:"master_generator" default:"false"` - CorsEnabled bool `yaml:"cors_enabled" default:"false"` - SecurityEnabled bool `yaml:"security_enabled" default:"false"` - } - Log struct { - RequestLogFormat string `yaml:"request_log_format" default:"${remote_ip} ${account_name} ${uri} ${method} ${status}"` - } - StaticContents struct { - Enabled bool `default:"false"` - } - Swagger struct { - Enabled bool `default:"false"` - Path string - } - Security struct { - AuthPath []string `yaml:"auth_path"` - ExculdePath []string `yaml:"exclude_path"` - UserPath []string `yaml:"user_path"` - AdminPath []string `yaml:"admin_path"` - } -} - -const ( - // DEV represents development environment - DEV = "develop" - // PRD represents production environment - PRD = "production" - // DOC represents docker container - DOC = "docker" -) - -// LoadAppConfig reads the settings written to the yml file -func LoadAppConfig(yamlFile embed.FS) (*Config, string) { - var env *string - if value := os.Getenv("WEB_APP_ENV"); value != "" { - env = &value - } else { - env = flag.String("env", "develop", "To switch configurations.") - flag.Parse() - } - - file, err := yamlFile.ReadFile(fmt.Sprintf(AppConfigPath, *env)) - if err != nil { - fmt.Printf("Failed to read application.%s.yml: %s", *env, err) - os.Exit(ErrExitStatus) - } - - config := &Config{} - if err := yaml.Unmarshal(file, config); err != nil { - fmt.Printf("Failed to read application.%s.yml: %s", *env, err) - os.Exit(ErrExitStatus) - } - - return config, *env -} - -// LoadMessagesConfig loads the messages.properties. -func LoadMessagesConfig(propsFile embed.FS) map[string]string { - messages := util.ReadPropertiesFile(propsFile, MessagesConfigPath) - if messages == nil { - fmt.Printf("Failed to load the messages.properties.") - os.Exit(ErrExitStatus) - } - return messages -} diff --git a/src/sample-golang-echo-app/config/const.go b/src/sample-golang-echo-app/config/const.go deleted file mode 100644 index f4c1ef26311c018071ae8ce7c84fb5f21819dc1a..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/config/const.go +++ /dev/null @@ -1,47 +0,0 @@ -package config - -// ErrExitStatus represents the error status in this application. -const ErrExitStatus int = 2 - -const ( - // AppConfigPath is the path of application.yml. - AppConfigPath = "resources/config/application.%s.yml" - // MessagesConfigPath is the path of messages.properties. - MessagesConfigPath = "resources/config/messages.properties" - // LoggerConfigPath is the path of zaplogger.yml. - LoggerConfigPath = "resources/config/zaplogger.%s.yml" -) - -// PasswordHashCost is hash cost for a password. -const PasswordHashCost int = 10 - -const ( - // API represents the group of API. - API = "/api" - // APIBooks represents the group of book management API. - APIBooks = API + "/books" - // APIBooksID represents the API to get book data using id. - APIBooksID = APIBooks + "/:id" - // APICategories represents the group of category management API. - APICategories = API + "/categories" - // APIFormats represents the group of format management API. - APIFormats = API + "/formats" -) - -const ( - // APIAccount represents the group of auth management API. - APIAccount = API + "/auth" - // APIAccountLoginStatus represents the API to get the status of logged in account. - APIAccountLoginStatus = APIAccount + "/loginStatus" - // APIAccountLoginAccount represents the API to get the logged in account. - APIAccountLoginAccount = APIAccount + "/loginAccount" - // APIAccountLogin represents the API to login by session authentication. - APIAccountLogin = APIAccount + "/login" - // APIAccountLogout represents the API to logout. - APIAccountLogout = APIAccount + "/logout" -) - -const ( - // APIHealth represents the API to get the status of this application. - APIHealth = API + "/health" -) diff --git a/src/sample-golang-echo-app/container/container.go b/src/sample-golang-echo-app/container/container.go deleted file mode 100644 index e7a12d824b5205428c9deb918d50cfa109fa7bae..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/container/container.go +++ /dev/null @@ -1,65 +0,0 @@ -package container - -import ( - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/logger" - "github.com/ybkuroki/go-webapp-sample/repository" - "github.com/ybkuroki/go-webapp-sample/session" -) - -// Container represents a interface for accessing the data which sharing in overall application. -type Container interface { - GetRepository() repository.Repository - GetSession() session.Session - GetConfig() *config.Config - GetMessages() map[string]string - GetLogger() logger.Logger - GetEnv() string -} - -// container struct is for sharing data which such as database setting, the setting of application and logger in overall this application. -type container struct { - rep repository.Repository - session session.Session - config *config.Config - messages map[string]string - logger logger.Logger - env string -} - -// NewContainer is constructor. -func NewContainer(rep repository.Repository, s session.Session, config *config.Config, - messages map[string]string, logger logger.Logger, env string) Container { - return &container{rep: rep, session: s, config: config, - messages: messages, logger: logger, env: env} -} - -// GetRepository returns the object of repository. -func (c *container) GetRepository() repository.Repository { - return c.rep -} - -// GetSession returns the object of session. -func (c *container) GetSession() session.Session { - return c.session -} - -// GetConfig returns the object of configuration. -func (c *container) GetConfig() *config.Config { - return c.config -} - -// GetMessages returns the map has key and message. -func (c *container) GetMessages() map[string]string { - return c.messages -} - -// GetLogger returns the object of logger. -func (c *container) GetLogger() logger.Logger { - return c.logger -} - -// GetEnv returns the running environment. -func (c *container) GetEnv() string { - return c.env -} diff --git a/src/sample-golang-echo-app/controller/account.go b/src/sample-golang-echo-app/controller/account.go deleted file mode 100644 index a1db16c035307cb90e99e431ada22d844dfdd30e..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/account.go +++ /dev/null @@ -1,108 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/model" - "github.com/ybkuroki/go-webapp-sample/model/dto" - "github.com/ybkuroki/go-webapp-sample/service" -) - -// AccountController is a controller for managing user account. -type AccountController interface { - GetLoginStatus(c echo.Context) error - GetLoginAccount(c echo.Context) error - Login(c echo.Context) error - Logout(c echo.Context) error -} - -type accountController struct { - context container.Container - service service.AccountService - dummyAccount *model.Account -} - -// NewAccountController is constructor. -func NewAccountController(container container.Container) AccountController { - return &accountController{ - context: container, - service: service.NewAccountService(container), - dummyAccount: model.NewAccountWithPlainPassword("test", "test", 1), - } -} - -// GetLoginStatus returns the status of login. -// @Summary Get the login status. -// @Description Get the login status of current logged-in user. -// @Tags Auth -// @Accept json -// @Produce json -// @Success 200 {boolean} bool "The current user have already logged-in. Returns true." -// @Failure 401 {boolean} bool "The current user haven't logged-in yet. Returns false." -// @Router /auth/loginStatus [get] -func (controller *accountController) GetLoginStatus(c echo.Context) error { - return c.JSON(http.StatusOK, true) -} - -// GetLoginAccount returns the account data of logged in user. -// @Summary Get the account data of logged-in user. -// @Description Get the account data of logged-in user. -// @Tags Auth -// @Accept json -// @Produce json -// @Success 200 {object} model.Account "Success to fetch the account data. If the security function is disable, it returns the dummy data." -// @Failure 401 {boolean} bool "The current user haven't logged-in yet. Returns false." -// @Router /auth/loginAccount [get] -func (controller *accountController) GetLoginAccount(c echo.Context) error { - if !controller.context.GetConfig().Extension.SecurityEnabled { - return c.JSON(http.StatusOK, controller.dummyAccount) - } - return c.JSON(http.StatusOK, controller.context.GetSession().GetAccount()) -} - -// Login is the method to login using username and password by http post. -// @Summary Login using username and password. -// @Description Login using username and password. -// @Tags Auth -// @Accept json -// @Produce json -// @Param data body dto.LoginDto true "User name and Password for logged-in." -// @Success 200 {object} model.Account "Success to the authentication." -// @Failure 401 {boolean} bool "Failed to the authentication." -// @Router /auth/login [post] -func (controller *accountController) Login(c echo.Context) error { - dto := dto.NewLoginDto() - if err := c.Bind(dto); err != nil { - return c.JSON(http.StatusBadRequest, dto) - } - - sess := controller.context.GetSession() - if account := sess.GetAccount(); account != nil { - return c.JSON(http.StatusOK, account) - } - - authenticate, a := controller.service.AuthenticateByUsernameAndPassword(dto.UserName, dto.Password) - if authenticate { - _ = sess.SetAccount(a) - _ = sess.Save() - return c.JSON(http.StatusOK, a) - } - return c.NoContent(http.StatusUnauthorized) -} - -// Logout is the method to logout by http post. -// @Summary Logout. -// @Description Logout. -// @Tags Auth -// @Accept json -// @Produce json -// @Success 200 -// @Router /auth/logout [post] -func (controller *accountController) Logout(c echo.Context) error { - sess := controller.context.GetSession() - _ = sess.SetAccount(nil) - _ = sess.Delete() - return c.NoContent(http.StatusOK) -} diff --git a/src/sample-golang-echo-app/controller/account_test.go b/src/sample-golang-echo-app/controller/account_test.go deleted file mode 100644 index 2aab8359f636458e88377596298c1bf01cf3f030..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/account_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/model" - "github.com/ybkuroki/go-webapp-sample/model/dto" - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestGetLoginStatus_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - account := NewAccountController(container) - router.GET(config.APIAccountLoginStatus, func(c echo.Context) error { return account.GetLoginStatus(c) }) - - req := httptest.NewRequest("GET", config.APIAccountLoginStatus, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, "true", rec.Body.String()) -} - -func TestGetLoginAccount_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - account := NewAccountController(container) - router.GET(config.APIAccountLoginAccount, func(c echo.Context) error { return account.GetLoginAccount(c) }) - - req := httptest.NewRequest("GET", config.APIAccountLoginAccount, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - entity := model.NewAccountWithPlainPassword("test", "test", 1) - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(entity), rec.Body.String()) -} - -func TestLogin_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(true) - - account := NewAccountController(container) - router.POST(config.APIAccountLogin, func(c echo.Context) error { return account.Login(c) }) - - param := createLoginSuccessAccount() - req := test.NewJSONRequest("POST", config.APIAccountLogin, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.NotEmpty(t, test.GetCookie(rec, "GSESSION")) -} - -func TestLogin_AuthenticationFailure(t *testing.T) { - router, container := test.PrepareForControllerTest(true) - - account := NewAccountController(container) - router.POST(config.APIAccountLogin, func(c echo.Context) error { return account.Login(c) }) - - param := createLoginFailureAccount() - req := test.NewJSONRequest("POST", config.APIAccountLogin, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusUnauthorized, rec.Code) - assert.Empty(t, test.GetCookie(rec, "GSESSION")) -} - -func TestLogout_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(true) - - account := NewAccountController(container) - router.POST(config.APIAccountLogout, func(c echo.Context) error { return account.Logout(c) }) - - req := test.NewJSONRequest("POST", config.APIAccountLogout, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.NotEmpty(t, test.GetCookie(rec, "GSESSION")) -} - -func createLoginSuccessAccount() *dto.LoginDto { - return &dto.LoginDto{ - UserName: "test", - Password: "test", - } -} - -func createLoginFailureAccount() *dto.LoginDto { - return &dto.LoginDto{ - UserName: "test", - Password: "abcde", - } -} diff --git a/src/sample-golang-echo-app/controller/book.go b/src/sample-golang-echo-app/controller/book.go deleted file mode 100644 index 2b6de4e1bfa7ea912a3a11be253a0aefb8173af1..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/book.go +++ /dev/null @@ -1,135 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/model/dto" - "github.com/ybkuroki/go-webapp-sample/service" -) - -// BookController is a controller for managing books. -type BookController interface { - GetBook(c echo.Context) error - GetBookList(c echo.Context) error - CreateBook(c echo.Context) error - UpdateBook(c echo.Context) error - DeleteBook(c echo.Context) error -} - -type bookController struct { - container container.Container - service service.BookService -} - -// NewBookController is constructor. -func NewBookController(container container.Container) BookController { - return &bookController{container: container, service: service.NewBookService(container)} -} - -// GetBook returns one record matched book's id. -// @Summary Get a book -// @Description Get a book -// @Tags Books -// @Accept json -// @Produce json -// @Param book_id path int true "Book ID" -// @Success 200 {object} model.Book "Success to fetch data." -// @Failure 400 {string} message "Failed to fetch data." -// @Failure 401 {boolean} bool "Failed to the authentication. Returns false." -// @Router /books/{book_id} [get] -func (controller *bookController) GetBook(c echo.Context) error { - book, err := controller.service.FindByID(c.Param("id")) - if err != nil { - return c.JSON(http.StatusBadRequest, err.Error()) - } - return c.JSON(http.StatusOK, book) -} - -// GetBookList returns the list of matched books by searching. -// @Summary Get a book list -// @Description Get the list of matched books by searching -// @Tags Books -// @Accept json -// @Produce json -// @Param query query string false "Keyword" -// @Param page query int false "Page number" -// @Param size query int false "Item size per page" -// @Success 200 {object} model.Page "Success to fetch a book list." -// @Failure 400 {string} message "Failed to fetch data." -// @Failure 401 {boolean} bool "Failed to the authentication. Returns false." -// @Router /books [get] -func (controller *bookController) GetBookList(c echo.Context) error { - book, err := controller.service.FindBooksByTitle(c.QueryParam("query"), c.QueryParam("page"), c.QueryParam("size")) - if err != nil { - return c.JSON(http.StatusBadRequest, err.Error()) - } - return c.JSON(http.StatusOK, book) -} - -// CreateBook create a new book by http post. -// @Summary Create a new book -// @Description Create a new book -// @Tags Books -// @Accept json -// @Produce json -// @Param data body dto.BookDto true "a new book data for creating" -// @Success 200 {object} model.Book "Success to create a new book." -// @Failure 400 {string} message "Failed to the registration." -// @Failure 401 {boolean} bool "Failed to the authentication. Returns false." -// @Router /books [post] -func (controller *bookController) CreateBook(c echo.Context) error { - dto := dto.NewBookDto(controller.container.GetMessages()) - if err := c.Bind(dto); err != nil { - return c.JSON(http.StatusBadRequest, dto) - } - book, result := controller.service.CreateBook(dto) - if result != nil { - return c.JSON(http.StatusBadRequest, result) - } - return c.JSON(http.StatusOK, book) -} - -// UpdateBook update the existing book by http put. -// @Summary Update the existing book -// @Description Update the existing book -// @Tags Books -// @Accept json -// @Produce json -// @Param book_id path int true "Book ID" -// @Param data body dto.BookDto true "the book data for updating" -// @Success 200 {object} model.Book "Success to update the existing book." -// @Failure 400 {string} message "Failed to the update." -// @Failure 401 {boolean} bool "Failed to the authentication. Returns false." -// @Router /books/{book_id} [put] -func (controller *bookController) UpdateBook(c echo.Context) error { - dto := dto.NewBookDto(controller.container.GetMessages()) - if err := c.Bind(dto); err != nil { - return c.JSON(http.StatusBadRequest, dto) - } - book, result := controller.service.UpdateBook(dto, c.Param("id")) - if result != nil { - return c.JSON(http.StatusBadRequest, result) - } - return c.JSON(http.StatusOK, book) -} - -// DeleteBook deletes the existing book by http delete. -// @Summary Delete the existing book -// @Description Delete the existing book -// @Tags Books -// @Accept json -// @Produce json -// @Param book_id path int true "Book ID" -// @Success 200 {object} model.Book "Success to delete the existing book." -// @Failure 400 {string} message "Failed to the delete." -// @Failure 401 {boolean} bool "Failed to the authentication. Returns false." -// @Router /books/{book_id} [delete] -func (controller *bookController) DeleteBook(c echo.Context) error { - book, result := controller.service.DeleteBook(c.Param("id")) - if result != nil { - return c.JSON(http.StatusBadRequest, result) - } - return c.JSON(http.StatusOK, book) -} diff --git a/src/sample-golang-echo-app/controller/book_test.go b/src/sample-golang-echo-app/controller/book_test.go deleted file mode 100644 index 0f65e867f90b0d59356ea7dd816f82d809a64358..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/book_test.go +++ /dev/null @@ -1,310 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/model" - "github.com/ybkuroki/go-webapp-sample/model/dto" - "github.com/ybkuroki/go-webapp-sample/test" - "github.com/ybkuroki/go-webapp-sample/util" -) - -type BookDtoForBindError struct { - Title string - Isbn string - CategoryID string - FormatID string -} - -const ( - ValidationErrMessageBookTitle string = "Please enter the title with 3 to 50 characters." - ValidationErrMessageBookISBN string = "Please enter the ISBN with 10 to 20 characters." -) - -func TestGetBook_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.GET(config.APIBooksID, func(c echo.Context) error { return book.GetBook(c) }) - - setUpTestData(container) - - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := httptest.NewRequest("GET", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - entity := &model.Book{} - opt := entity.FindByID(container.GetRepository(), 1) - data, _ := opt.Take() - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} - -func TestGetBook_Failure(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.GET(config.APIBooksID, func(c echo.Context) error { return book.GetBook(c) }) - - setUpTestData(container) - - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("9999").Build().GetRequestURL() - req := httptest.NewRequest("GET", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.Equal(t, "\"none value taken\"\n", rec.Body.String()) -} - -func TestGetBookList_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.GET(config.APIBooks, func(c echo.Context) error { return book.GetBookList(c) }) - - setUpTestData(container) - - uri := util.NewRequestBuilder().URL(config.APIBooks). - RequestParams("query", "Test").RequestParams("page", "0").RequestParams("size", "5"). - Build().GetRequestURL() - req := httptest.NewRequest("GET", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - entity := &model.Book{} - data, _ := entity.FindByTitle(container.GetRepository(), "Test", "0", "5") - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} - -func TestCreateBook_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.POST(config.APIBooks, func(c echo.Context) error { return book.CreateBook(c) }) - - param := createBookForCreate() - req := test.NewJSONRequest("POST", config.APIBooks, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - entity := &model.Book{} - opt := entity.FindByID(container.GetRepository(), 1) - data, _ := opt.Take() - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} - -func TestCreateBook_BindError(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.POST(config.APIBooks, func(c echo.Context) error { return book.CreateBook(c) }) - - param := createBookForBindError() - req := test.NewJSONRequest("POST", config.APIBooks, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - result := createResultForBindError() - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.JSONEq(t, test.ConvertToString(result), rec.Body.String()) -} - -func TestCreateBook_ValidationError(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.POST(config.APIBooks, func(c echo.Context) error { return book.CreateBook(c) }) - - param := createBookForValidationError() - req := test.NewJSONRequest("POST", config.APIBooks, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - result := createResultForValidationError() - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.JSONEq(t, test.ConvertToString(result), rec.Body.String()) -} - -func TestUpdateBook_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.PUT(config.APIBooksID, func(c echo.Context) error { return book.UpdateBook(c) }) - - setUpTestData(container) - - param := createBookForUpdate() - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := test.NewJSONRequest("PUT", uri, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - entity := &model.Book{} - opt := entity.FindByID(container.GetRepository(), 1) - data, _ := opt.Take() - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} - -func TestUpdateBook_BindError(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.PUT(config.APIBooksID, func(c echo.Context) error { return book.UpdateBook(c) }) - - setUpTestData(container) - - param := createBookForBindError() - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := test.NewJSONRequest("PUT", uri, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - result := createResultForBindError() - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.JSONEq(t, test.ConvertToString(result), rec.Body.String()) -} - -func TestUpdateBook_ValidationError(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.PUT(config.APIBooksID, func(c echo.Context) error { return book.UpdateBook(c) }) - - setUpTestData(container) - - param := createBookForValidationError() - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := test.NewJSONRequest("PUT", uri, param) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - result := createResultForValidationError() - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.JSONEq(t, test.ConvertToString(result), rec.Body.String()) -} - -func TestDeleteBook_Success(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.DELETE(config.APIBooksID, func(c echo.Context) error { return book.DeleteBook(c) }) - - setUpTestData(container) - - entity := &model.Book{} - opt := entity.FindByID(container.GetRepository(), 1) - data, _ := opt.Take() - - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := test.NewJSONRequest("DELETE", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} - -func TestDeleteBook_Failure(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - book := NewBookController(container) - router.DELETE(config.APIBooksID, func(c echo.Context) error { return book.DeleteBook(c) }) - - setUpTestData(container) - - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("9999").Build().GetRequestURL() - req := test.NewJSONRequest("DELETE", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.JSONEq(t, test.ConvertToString(createResultForDeleteError()), rec.Body.String()) -} - -func setUpTestData(container container.Container) { - model := model.NewBook("Test1", "123-123-123-1", 1, 1) - repo := container.GetRepository() - _, _ = model.Create(repo) -} - -func createBookForCreate() *dto.BookDto { - return &dto.BookDto{ - Title: "Test1", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - } -} - -func createBookForValidationError() *dto.BookDto { - return &dto.BookDto{ - Title: "T", - Isbn: "123", - CategoryID: 1, - FormatID: 1, - } -} - -func createBookForBindError() *BookDtoForBindError { - return &BookDtoForBindError{ - Title: "Test1", - Isbn: "123-123-123-1", - CategoryID: "Test", - FormatID: "Test", - } -} - -func createResultForBindError() *dto.BookDto { - return &dto.BookDto{ - Title: "Test1", - Isbn: "123-123-123-1", - CategoryID: 0, - FormatID: 0, - } -} - -func createResultForValidationError() map[string]string { - return map[string]string{ - "isbn": ValidationErrMessageBookISBN, - "title": ValidationErrMessageBookTitle, - } -} - -func createResultForDeleteError() map[string]string { - return map[string]string{"error": "Failed to the delete"} -} - -func createBookForUpdate() *dto.BookDto { - return &dto.BookDto{ - Title: "Test2", - Isbn: "123-123-123-2", - CategoryID: 2, - FormatID: 2, - } -} diff --git a/src/sample-golang-echo-app/controller/category.go b/src/sample-golang-echo-app/controller/category.go deleted file mode 100644 index 9f39850e8c799ac3bc556eeab1abbdc25c6889a8..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/category.go +++ /dev/null @@ -1,37 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/service" -) - -// CategoryController is a controller for managing category data. -type CategoryController interface { - GetCategoryList(c echo.Context) error -} - -type categoryController struct { - container container.Container - service service.CategoryService -} - -// NewCategoryController is constructor. -func NewCategoryController(container container.Container) CategoryController { - return &categoryController{container: container, service: service.NewCategoryService(container)} -} - -// GetCategoryList returns the list of all categories. -// @Summary Get a category list -// @Description Get a category list -// @Tags Categories -// @Accept json -// @Produce json -// @Success 200 {array} model.Category "Success to fetch a category list." -// @Failure 401 {string} false "Failed to the authentication." -// @Router /categories [get] -func (controller *categoryController) GetCategoryList(c echo.Context) error { - return c.JSON(http.StatusOK, controller.service.FindAllCategories()) -} diff --git a/src/sample-golang-echo-app/controller/category_test.go b/src/sample-golang-echo-app/controller/category_test.go deleted file mode 100644 index a764fecc63df2535fbd94fb4f77fa9152d08d55e..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/category_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/model" - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestGetCategoryList(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - category := NewCategoryController(container) - router.GET(config.APICategories, func(c echo.Context) error { return category.GetCategoryList(c) }) - - req := httptest.NewRequest("GET", config.APICategories, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - data := [...]*model.Category{ - {ID: 1, Name: "Technical Book"}, - {ID: 2, Name: "Magazine"}, - {ID: 3, Name: "Novel"}, - } - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} diff --git a/src/sample-golang-echo-app/controller/error.go b/src/sample-golang-echo-app/controller/error.go deleted file mode 100644 index 0b0e90d9b7cce2ea192674f23019ff730369ce21..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/error.go +++ /dev/null @@ -1,51 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" -) - -// APIError has a error code and a message. -type APIError struct { - Code int - Message string -} - -// ErrorController is a controller for handling errors. -type ErrorController interface { - JSONError(err error, c echo.Context) -} - -type errorController struct { - container container.Container -} - -// NewErrorController is constructor. -func NewErrorController(container container.Container) ErrorController { - return &errorController{container: container} -} - -// JSONError is cumstomize error handler -func (controller *errorController) JSONError(err error, c echo.Context) { - logger := controller.container.GetLogger() - code := http.StatusInternalServerError - msg := http.StatusText(code) - - if he, ok := err.(*echo.HTTPError); ok { - code = he.Code - msg = he.Message.(string) - } - - var apierr APIError - apierr.Code = code - apierr.Message = msg - - if !c.Response().Committed { - if reserr := c.JSON(code, apierr); reserr != nil { - logger.GetZapLogger().Errorf(reserr.Error()) - } - } - logger.GetZapLogger().Debugf(err.Error()) -} diff --git a/src/sample-golang-echo-app/controller/error_test.go b/src/sample-golang-echo-app/controller/error_test.go deleted file mode 100644 index 1fa2f5af7d2782755d84f4a593df856b0fe7d861..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/error_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestJSONError(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - errorHandler := NewErrorController(container) - router.HTTPErrorHandler = errorHandler.JSONError - - req := httptest.NewRequest("GET", "/api/movies/1", nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusNotFound, rec.Code) - assert.JSONEq(t, `{"Code":404,"Message":"Not Found"}`, rec.Body.String()) -} diff --git a/src/sample-golang-echo-app/controller/format.go b/src/sample-golang-echo-app/controller/format.go deleted file mode 100644 index dd5d3dd8cfce10e65b122720e8b0b6da27d98c1e..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/format.go +++ /dev/null @@ -1,37 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/service" -) - -// FormatController is a controller for managing format data. -type FormatController interface { - GetFormatList(c echo.Context) error -} - -type formatController struct { - container container.Container - service service.FormatService -} - -// NewFormatController is constructor. -func NewFormatController(container container.Container) FormatController { - return &formatController{container: container, service: service.NewFormatService(container)} -} - -// GetFormatList returns the list of all formats. -// @Summary Get a format list -// @Description Get a format list -// @Tags Formats -// @Accept json -// @Produce json -// @Success 200 {array} model.Format "Success to fetch a format list." -// @Failure 401 {string} false "Failed to the authentication." -// @Router /formats [get] -func (controller *formatController) GetFormatList(c echo.Context) error { - return c.JSON(http.StatusOK, controller.service.FindAllFormats()) -} diff --git a/src/sample-golang-echo-app/controller/format_test.go b/src/sample-golang-echo-app/controller/format_test.go deleted file mode 100644 index 88ea18a2aa7b350671a70f47e6c63ac4f1d9cb4b..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/format_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/model" - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestGetFormatList(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - format := NewFormatController(container) - router.GET(config.APIFormats, func(c echo.Context) error { return format.GetFormatList(c) }) - - req := httptest.NewRequest("GET", config.APIFormats, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - data := [...]*model.Format{ - {ID: 1, Name: "Paper Book"}, - {ID: 2, Name: "e-Book"}, - } - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) -} diff --git a/src/sample-golang-echo-app/controller/health.go b/src/sample-golang-echo-app/controller/health.go deleted file mode 100644 index f6fac2aae08789335da579a87bc79efe417d965f..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/health.go +++ /dev/null @@ -1,35 +0,0 @@ -package controller - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/ybkuroki/go-webapp-sample/container" -) - -// HealthController is a controller returns the current status of this application. -type HealthController interface { - GetHealthCheck(c echo.Context) error -} - -type healthController struct { - container container.Container -} - -// NewHealthController is constructor. -func NewHealthController(container container.Container) HealthController { - return &healthController{container: container} -} - -// GetHealthCheck returns whether this application is alive or not. -// @Summary Get the status of this application -// @Description Get the status of this application -// @Tags Health -// @Accept json -// @Produce json -// @Success 200 {string} message "healthy: This application is started." -// @Failure 404 {string} message "None: This application is stopped." -// @Router /health [get] -func (controller *healthController) GetHealthCheck(c echo.Context) error { - return c.JSON(http.StatusOK, "healthy") -} diff --git a/src/sample-golang-echo-app/controller/health_test.go b/src/sample-golang-echo-app/controller/health_test.go deleted file mode 100644 index 3f49c4cef465b853c4dc72781e5d1b28f1677d60..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/health_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestGetHealthCheck(t *testing.T) { - router, container := test.PrepareForControllerTest(false) - - health := NewHealthController(container) - router.GET(config.APIHealth, func(c echo.Context) error { return health.GetHealthCheck(c) }) - - req := httptest.NewRequest("GET", config.APIHealth, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.JSONEq(t, `"healthy"`, rec.Body.String()) -} diff --git a/src/sample-golang-echo-app/controller/logger_test.go b/src/sample-golang-echo-app/controller/logger_test.go deleted file mode 100644 index 8db6e9962fa91e245352b47f5bae6a1d6831851c..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/logger_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package controller - -import ( - "net/http/httptest" - "strings" - "testing" - - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/test" - "github.com/ybkuroki/go-webapp-sample/util" - "go.uber.org/zap/zaptest/observer" -) - -func TestLogging(t *testing.T) { - router, container, logs := test.PrepareForLoggerTest() - - book := NewBookController(container) - router.GET(config.APIBooksID, func(c echo.Context) error { return book.GetBook(c) }) - - setUpTestData(container) - - uri := util.NewRequestBuilder().URL(config.APIBooks).PathParams("1").Build().GetRequestURL() - req := httptest.NewRequest("GET", uri, nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - allLogs := logs.All() - assert.True(t, assertLogger("/api/books/:id Action Start", allLogs)) - assert.True(t, assertLogger("/api/books/:id Action End", allLogs)) - assert.True(t, assertLogger("/api/books/1 GET 200", allLogs)) - assert.True(t, assertLogger("[gorm] ", allLogs)) -} - -func assertLogger(message string, logs []observer.LoggedEntry) bool { - for _, l := range logs { - if strings.Contains(l.Message, message) { - return true - } - } - return false -} diff --git a/src/sample-golang-echo-app/controller/swagger_test.go b/src/sample-golang-echo-app/controller/swagger_test.go deleted file mode 100644 index 4397a5bfdeda0154d1bf960274275f1b11fa6c15..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/controller/swagger_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package controller - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - echoSwagger "github.com/swaggo/echo-swagger" - _ "github.com/ybkuroki/go-webapp-sample/docs" // for using echo-swagger - "github.com/ybkuroki/go-webapp-sample/test" -) - -func TestSwagger(t *testing.T) { - router, _ := test.PrepareForControllerTest(false) - router.GET("/swagger/*", echoSwagger.WrapHandler) - - req := httptest.NewRequest("GET", "/swagger/index.html", nil) - rec := httptest.NewRecorder() - - router.ServeHTTP(rec, req) - - assert.Equal(t, http.StatusOK, rec.Code) - assert.Regexp(t, "Swagger UI", rec.Body.String()) -} diff --git a/src/sample-golang-echo-app/docs/docs.go b/src/sample-golang-echo-app/docs/docs.go deleted file mode 100644 index abce2a9b2334cc0361261ef4ef85f3701bb8912c..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/docs/docs.go +++ /dev/null @@ -1,671 +0,0 @@ -// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag - -package docs - -import ( - "bytes" - "encoding/json" - "strings" - - "github.com/alecthomas/template" - "github.com/swaggo/swag" -) - -var doc = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{.Description}}", - "title": "{{.Title}}", - "contact": {}, - "license": { - "name": "MIT", - "url": "https://opensource.org/licenses/mit-license.php" - }, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/auth/login": { - "post": { - "description": "Login using username and password.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Auth" - ], - "summary": "Login using username and password.", - "parameters": [ - { - "description": "User name and Password for logged-in.", - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dto.LoginDto" - } - } - ], - "responses": { - "200": { - "description": "Success to the authentication.", - "schema": { - "$ref": "#/definitions/model.Account" - } - }, - "401": { - "description": "Failed to the authentication.", - "schema": { - "type": "boolean" - } - } - } - } - }, - "/auth/loginAccount": { - "get": { - "description": "Get the account data of logged-in user.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Auth" - ], - "summary": "Get the account data of logged-in user.", - "responses": { - "200": { - "description": "Success to fetch the account data. If the security function is disable, it returns the dummy data.", - "schema": { - "$ref": "#/definitions/model.Account" - } - }, - "401": { - "description": "The current user haven't logged-in yet. Returns false.", - "schema": { - "type": "boolean" - } - } - } - } - }, - "/auth/loginStatus": { - "get": { - "description": "Get the login status of current logged-in user.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Auth" - ], - "summary": "Get the login status.", - "responses": { - "200": { - "description": "The current user have already logged-in. Returns true.", - "schema": { - "type": "boolean" - } - }, - "401": { - "description": "The current user haven't logged-in yet. Returns false.", - "schema": { - "type": "boolean" - } - } - } - } - }, - "/auth/logout": { - "post": { - "description": "Logout.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Auth" - ], - "summary": "Logout.", - "responses": { - "200": { - "description": "" - } - } - } - }, - "/books": { - "get": { - "description": "Get the list of matched books by searching", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Books" - ], - "summary": "Get a book list", - "parameters": [ - { - "type": "string", - "description": "Keyword", - "name": "query", - "in": "query" - }, - { - "type": "integer", - "description": "Page number", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "Item size per page", - "name": "size", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Success to fetch a book list.", - "schema": { - "$ref": "#/definitions/model.Page" - } - }, - "400": { - "description": "Failed to fetch data.", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Failed to the authentication. Returns false.", - "schema": { - "type": "boolean" - } - } - } - }, - "post": { - "description": "Create a new book", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Books" - ], - "summary": "Create a new book", - "parameters": [ - { - "description": "a new book data for creating", - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dto.BookDto" - } - } - ], - "responses": { - "200": { - "description": "Success to create a new book.", - "schema": { - "$ref": "#/definitions/model.Book" - } - }, - "400": { - "description": "Failed to the registration.", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Failed to the authentication. Returns false.", - "schema": { - "type": "boolean" - } - } - } - } - }, - "/books/{book_id}": { - "get": { - "description": "Get a book", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Books" - ], - "summary": "Get a book", - "parameters": [ - { - "type": "integer", - "description": "Book ID", - "name": "book_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success to fetch data.", - "schema": { - "$ref": "#/definitions/model.Book" - } - }, - "400": { - "description": "Failed to fetch data.", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Failed to the authentication. Returns false.", - "schema": { - "type": "boolean" - } - } - } - }, - "put": { - "description": "Update the existing book", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Books" - ], - "summary": "Update the existing book", - "parameters": [ - { - "type": "integer", - "description": "Book ID", - "name": "book_id", - "in": "path", - "required": true - }, - { - "description": "the book data for updating", - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/dto.BookDto" - } - } - ], - "responses": { - "200": { - "description": "Success to update the existing book.", - "schema": { - "$ref": "#/definitions/model.Book" - } - }, - "400": { - "description": "Failed to the update.", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Failed to the authentication. Returns false.", - "schema": { - "type": "boolean" - } - } - } - }, - "delete": { - "description": "Delete the existing book", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Books" - ], - "summary": "Delete the existing book", - "parameters": [ - { - "type": "integer", - "description": "Book ID", - "name": "book_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success to delete the existing book.", - "schema": { - "$ref": "#/definitions/model.Book" - } - }, - "400": { - "description": "Failed to the delete.", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Failed to the authentication. Returns false.", - "schema": { - "type": "boolean" - } - } - } - } - }, - "/categories": { - "get": { - "description": "Get a category list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Categories" - ], - "summary": "Get a category list", - "responses": { - "200": { - "description": "Success to fetch a category list.", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Category" - } - } - }, - "401": { - "description": "Failed to the authentication.", - "schema": { - "type": "string" - } - } - } - } - }, - "/formats": { - "get": { - "description": "Get a format list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Formats" - ], - "summary": "Get a format list", - "responses": { - "200": { - "description": "Success to fetch a format list.", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Format" - } - } - }, - "401": { - "description": "Failed to the authentication.", - "schema": { - "type": "string" - } - } - } - } - }, - "/health": { - "get": { - "description": "Get the status of this application", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Health" - ], - "summary": "Get the status of this application", - "responses": { - "200": { - "description": "healthy: This application is started.", - "schema": { - "type": "string" - } - }, - "404": { - "description": "None: This application is stopped.", - "schema": { - "type": "string" - } - } - } - } - } - }, - "definitions": { - "dto.BookDto": { - "type": "object", - "required": [ - "isbn", - "title" - ], - "properties": { - "categoryId": { - "type": "integer" - }, - "formatId": { - "type": "integer" - }, - "isbn": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "dto.LoginDto": { - "type": "object", - "properties": { - "password": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "model.Account": { - "type": "object", - "properties": { - "authority": { - "$ref": "#/definitions/model.Authority" - }, - "authority_id": { - "type": "integer" - }, - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "model.Authority": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "model.Book": { - "type": "object", - "properties": { - "category": { - "$ref": "#/definitions/model.Category" - }, - "categoryId": { - "type": "integer" - }, - "format": { - "$ref": "#/definitions/model.Format" - }, - "formatId": { - "type": "integer" - }, - "id": { - "type": "integer" - }, - "isbn": { - "type": "string" - }, - "title": { - "type": "string" - } - } - }, - "model.Category": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "model.Format": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "model.Page": { - "type": "object", - "properties": { - "content": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Book" - } - }, - "last": { - "type": "boolean" - }, - "numberOfElements": { - "type": "integer" - }, - "page": { - "type": "integer" - }, - "size": { - "type": "integer" - }, - "totalElements": { - "type": "integer" - }, - "totalPages": { - "type": "integer" - } - } - } - } -}` - -type swaggerInfo struct { - Version string - Host string - BasePath string - Schemes []string - Title string - Description string -} - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = swaggerInfo{ - Version: "1.5.1", - Host: "localhost:8080", - BasePath: "/api", - Schemes: []string{}, - Title: "go-webapp-sample API", - Description: "This is API specification for go-webapp-sample project.", -} - -type s struct{} - -func (s *s) ReadDoc() string { - sInfo := SwaggerInfo - sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) - - t, err := template.New("swagger_info").Funcs(template.FuncMap{ - "marshal": func(v interface{}) string { - a, _ := json.Marshal(v) - return string(a) - }, - }).Parse(doc) - if err != nil { - return doc - } - - var tpl bytes.Buffer - if err := t.Execute(&tpl, sInfo); err != nil { - return doc - } - - return tpl.String() -} - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/src/sample-golang-echo-app/go.mod b/src/sample-golang-echo-app/go.mod deleted file mode 100644 index 1232327bb266222209789e03fef33218f16511f7..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/go.mod +++ /dev/null @@ -1,65 +0,0 @@ -module github.com/ybkuroki/go-webapp-sample - -go 1.20 - -require ( - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/garyburd/redigo v1.6.4 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/gorilla/sessions v1.2.1 - github.com/labstack/echo-contrib v0.15.0 - github.com/labstack/echo/v4 v4.10.2 - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect - github.com/moznion/go-optional v0.10.0 - github.com/stretchr/testify v1.8.4 - github.com/swaggo/echo-swagger v1.4.0 - github.com/swaggo/swag v1.16.1 - github.com/valyala/fasttemplate v1.2.2 - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.9.0 - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/tools v0.9.3 // indirect - gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/go-playground/validator.v9 v9.31.0 - gopkg.in/natefinch/lumberjack.v2 v2.2.1 - gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.1 - gorm.io/driver/postgres v1.5.2 - gorm.io/driver/sqlite v1.5.1 - gorm.io/gorm v1.25.1 -) - -require ( - github.com/KyleBanks/depth v1.2.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-sql-driver/mysql v1.7.1 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/securecookie v1.1.1 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.3.1 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/labstack/gommon v0.4.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/swaggo/files/v2 v2.0.0 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.3.0 // indirect -) diff --git a/src/sample-golang-echo-app/go.sum b/src/sample-golang-echo-app/go.sum deleted file mode 100644 index 5d16da534715d34e4b652275cbc47a4e28c60dbe..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/go.sum +++ /dev/null @@ -1,165 +0,0 @@ -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= -github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg= -github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= -github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo-contrib v0.15.0 h1:9K+oRU265y4Mu9zpRDv3X+DGTqUALY6oRHCSZZKCRVU= -github.com/labstack/echo-contrib v0.15.0/go.mod h1:lei+qt5CLB4oa7VHTE0yEfQSEB9XTJI1LUqko9UWvo4= -github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= -github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= -github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/moznion/go-optional v0.10.0 h1:YE42pzLDp6vc9zi/2hyaHYJesjahZEgFXEN1u5DMwMA= -github.com/moznion/go-optional v0.10.0/go.mod h1:l3mLmsyp2bWTvWKjEm5MT7lo3g5MRlNIflxFB0XTASA= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/swaggo/echo-swagger v1.4.0 h1:RCxLKySw1SceHLqnmc41pKyiIeE+OiD7NSI7FUOBlLo= -github.com/swaggo/echo-swagger v1.4.0/go.mod h1:Wh3VlwjZGZf/LH0s81tz916JokuPG7y/ZqaqnckYqoQ= -github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= -github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= -github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= -github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b h1:U/Uqd1232+wrnHOvWNaxrNqn/kFnr4yu4blgPtQt0N8= -gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b/go.mod h1:fgfIZMlsafAHpspcks2Bul+MWUNw/2dyQmjC2faKjtg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= -gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= -gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= -gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= -gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4= -gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= -gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/src/sample-golang-echo-app/logger/gormlogger.go b/src/sample-golang-echo-app/logger/gormlogger.go deleted file mode 100644 index e1cf33116d895c5710f078993eae2f2c9cfb298c..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/logger/gormlogger.go +++ /dev/null @@ -1,60 +0,0 @@ -package logger - -import ( - "context" - "fmt" - "time" - - gormLogger "gorm.io/gorm/logger" - gormUtils "gorm.io/gorm/utils" -) - -// Customize SQL Logger for gorm library -// ref: https://github.com/wantedly/gorm-zap -// ref: https://github.com/go-gorm/gorm/blob/master/logger/logger.go - -const ( - logTitle = "[gorm] " - sqlFormat = logTitle + "%s" - messageFormat = logTitle + "%s, %s" - errorFormat = logTitle + "%s, %s, %s" - slowThreshold = 200 -) - -// LogMode The log level of gorm logger is overwrited by the log level of Zap logger. -func (log *logger) LogMode(_ gormLogger.LogLevel) gormLogger.Interface { - return log -} - -// Info prints a information log. -func (log *logger) Info(_ context.Context, msg string, data ...interface{}) { - log.Zap.Infof(messageFormat, append([]interface{}{msg, gormUtils.FileWithLineNum()}, data...)...) -} - -// Warn prints a warning log. -func (log *logger) Warn(_ context.Context, msg string, data ...interface{}) { - log.Zap.Warnf(messageFormat, append([]interface{}{msg, gormUtils.FileWithLineNum()}, data...)...) -} - -// Error prints a error log. -func (log *logger) Error(_ context.Context, msg string, data ...interface{}) { - log.Zap.Errorf(messageFormat, append([]interface{}{msg, gormUtils.FileWithLineNum()}, data...)...) -} - -// Trace prints a trace log such as sql, source file and error. -func (log *logger) Trace(_ context.Context, begin time.Time, fc func() (string, int64), err error) { - elapsed := time.Since(begin) - - switch { - case err != nil: - sql, _ := fc() - log.GetZapLogger().Errorf(errorFormat, gormUtils.FileWithLineNum(), err, sql) - case elapsed > slowThreshold*time.Millisecond && slowThreshold*time.Millisecond != 0: - sql, _ := fc() - slowLog := fmt.Sprintf("SLOW SQL >= %v", slowThreshold) - log.GetZapLogger().Warnf(errorFormat, gormUtils.FileWithLineNum(), slowLog, sql) - default: - sql, _ := fc() - log.GetZapLogger().Debugf(sqlFormat, sql) - } -} diff --git a/src/sample-golang-echo-app/logger/logger.go b/src/sample-golang-echo-app/logger/logger.go deleted file mode 100644 index 6c302027fe286d2cc4459dbf89264c1d32d79b4f..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/logger/logger.go +++ /dev/null @@ -1,71 +0,0 @@ -package logger - -import ( - "context" - "embed" - "fmt" - "os" - "time" - - "github.com/ybkuroki/go-webapp-sample/config" - "go.uber.org/zap" - "gopkg.in/natefinch/lumberjack.v2" - "gopkg.in/yaml.v3" - gormLogger "gorm.io/gorm/logger" -) - -// Config represents the setting for zap logger. -type Config struct { - ZapConfig zap.Config `json:"zap_config" yaml:"zap_config"` - LogRotate lumberjack.Logger `json:"log_rotate" yaml:"log_rotate"` -} - -// Logger is an alternative implementation of *gorm.Logger -type Logger interface { - GetZapLogger() *zap.SugaredLogger - LogMode(level gormLogger.LogLevel) gormLogger.Interface - Info(ctx context.Context, msg string, data ...interface{}) - Warn(ctx context.Context, msg string, data ...interface{}) - Error(ctx context.Context, msg string, data ...interface{}) - Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) -} - -type logger struct { - Zap *zap.SugaredLogger -} - -// NewLogger is constructor for logger -func NewLogger(sugar *zap.SugaredLogger) Logger { - return &logger{Zap: sugar} -} - -// InitLogger create logger object for *gorm.DB from *echo.Logger -func InitLogger(env string, yamlFile embed.FS) Logger { - configYaml, err := yamlFile.ReadFile(fmt.Sprintf(config.LoggerConfigPath, env)) - if err != nil { - fmt.Printf("Failed to read logger configuration: %s", err) - os.Exit(config.ErrExitStatus) - } - var myConfig *Config - if err = yaml.Unmarshal(configYaml, &myConfig); err != nil { - fmt.Printf("Failed to read zap logger configuration: %s", err) - os.Exit(config.ErrExitStatus) - } - var zap *zap.Logger - zap, err = build(myConfig) - if err != nil { - fmt.Printf("Failed to compose zap logger : %s", err) - os.Exit(config.ErrExitStatus) - } - sugar := zap.Sugar() - // set package varriable logger. - log := NewLogger(sugar) - log.GetZapLogger().Infof("Success to read zap logger configuration: zaplogger." + env + ".yml") - _ = zap.Sync() - return log -} - -// GetZapLogger returns zapSugaredLogger -func (log *logger) GetZapLogger() *zap.SugaredLogger { - return log.Zap -} diff --git a/src/sample-golang-echo-app/logger/zaplogger.go b/src/sample-golang-echo-app/logger/zaplogger.go deleted file mode 100644 index 417f788f83f68cb807515d5a9c1626fc4530cd11..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/logger/zaplogger.go +++ /dev/null @@ -1,88 +0,0 @@ -package logger - -import ( - "errors" - "os" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - "gopkg.in/natefinch/lumberjack.v2" -) - -func build(cfg *Config) (*zap.Logger, error) { - var zapCfg = cfg.ZapConfig - enc, _ := newEncoder(zapCfg) - writer, errWriter := openWriters(cfg) - - if zapCfg.Level == (zap.AtomicLevel{}) { - return nil, errors.New("missing Level") - } - - log := zap.New(zapcore.NewCore(enc, writer, zapCfg.Level), buildOptions(zapCfg, errWriter)...) - return log, nil -} - -func newEncoder(cfg zap.Config) (zapcore.Encoder, error) { - switch cfg.Encoding { - case "console": - return zapcore.NewConsoleEncoder(cfg.EncoderConfig), nil - case "json": - return zapcore.NewJSONEncoder(cfg.EncoderConfig), nil - } - return nil, errors.New("failed to set encoder") -} - -func openWriters(cfg *Config) (zapcore.WriteSyncer, zapcore.WriteSyncer) { - writer := open(cfg.ZapConfig.OutputPaths, &cfg.LogRotate) - errWriter := open(cfg.ZapConfig.ErrorOutputPaths, &cfg.LogRotate) - return writer, errWriter -} - -func open(paths []string, rotateCfg *lumberjack.Logger) zapcore.WriteSyncer { - writers := make([]zapcore.WriteSyncer, 0, len(paths)) - for _, path := range paths { - writer := newWriter(path, rotateCfg) - writers = append(writers, writer) - } - writer := zap.CombineWriteSyncers(writers...) - return writer -} - -func newWriter(path string, rotateCfg *lumberjack.Logger) zapcore.WriteSyncer { - switch path { - case "stdout": - return os.Stdout - case "stderr": - return os.Stderr - } - sink := zapcore.AddSync( - &lumberjack.Logger{ - Filename: path, - MaxSize: rotateCfg.MaxSize, - MaxBackups: rotateCfg.MaxBackups, - MaxAge: rotateCfg.MaxAge, - Compress: rotateCfg.Compress, - }, - ) - return sink -} - -func buildOptions(cfg zap.Config, errWriter zapcore.WriteSyncer) []zap.Option { - opts := []zap.Option{zap.ErrorOutput(errWriter)} - if cfg.Development { - opts = append(opts, zap.Development()) - } - - if !cfg.DisableCaller { - opts = append(opts, zap.AddCaller()) - } - - stackLevel := zap.ErrorLevel - if cfg.Development { - stackLevel = zap.WarnLevel - } - if !cfg.DisableStacktrace { - opts = append(opts, zap.AddStacktrace(stackLevel)) - } - return opts -} diff --git a/src/sample-golang-echo-app/main.go b/src/sample-golang-echo-app/main.go deleted file mode 100644 index 973e5c7373fec27894bca0c37935bc45be7d6fb0..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/main.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "embed" - - "github.com/labstack/echo/v4" - - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/logger" - "github.com/ybkuroki/go-webapp-sample/middleware" - "github.com/ybkuroki/go-webapp-sample/migration" - "github.com/ybkuroki/go-webapp-sample/repository" - "github.com/ybkuroki/go-webapp-sample/router" - "github.com/ybkuroki/go-webapp-sample/session" -) - -//go:embed resources/config/application.*.yml -var yamlFile embed.FS - -//go:embed resources/config/zaplogger.*.yml -var zapYamlFile embed.FS - -//go:embed resources/public/* -var staticFile embed.FS - -//go:embed resources/config/messages.properties -var propsFile embed.FS - -// @title go-webapp-sample API -// @version 1.5.1 -// @description This is API specification for go-webapp-sample project. - -// @license.name MIT -// @license.url https://opensource.org/licenses/mit-license.php - -// @host localhost:8080 -// @BasePath /api -func main() { - e := echo.New() - - conf, env := config.LoadAppConfig(yamlFile) - logger := logger.InitLogger(env, zapYamlFile) - logger.GetZapLogger().Infof("Loaded this configuration : application." + env + ".yml") - - messages := config.LoadMessagesConfig(propsFile) - logger.GetZapLogger().Infof("Loaded messages.properties") - - rep := repository.NewBookRepository(logger, conf) - sess := session.NewSession() - container := container.NewContainer(rep, sess, conf, messages, logger, env) - - migration.CreateDatabase(container) - migration.InitMasterData(container) - - router.Init(e, container) - middleware.InitLoggerMiddleware(e, container) - middleware.InitSessionMiddleware(e, container) - middleware.StaticContentsMiddleware(e, container, staticFile) - - if err := e.Start(":8080"); err != nil { - logger.GetZapLogger().Errorf(err.Error()) - } - - defer rep.Close() -} diff --git a/src/sample-golang-echo-app/middleware/middleware.go b/src/sample-golang-echo-app/middleware/middleware.go deleted file mode 100644 index 63333457cadf9e8c96cd827dd04e488a03665573..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/middleware/middleware.go +++ /dev/null @@ -1,183 +0,0 @@ -package middleware - -import ( - "embed" - "fmt" - "io" - "net/http" - "regexp" - "strconv" - - "github.com/gorilla/sessions" - "github.com/labstack/echo-contrib/session" - "github.com/labstack/echo/v4" - echomd "github.com/labstack/echo/v4/middleware" - "github.com/valyala/fasttemplate" - "github.com/ybkuroki/go-webapp-sample/container" - "gopkg.in/boj/redistore.v1" -) - -// InitLoggerMiddleware initialize a middleware for logger. -func InitLoggerMiddleware(e *echo.Echo, container container.Container) { - e.Use(RequestLoggerMiddleware(container)) - e.Use(ActionLoggerMiddleware(container)) -} - -// InitSessionMiddleware initialize a middleware for session management. -func InitSessionMiddleware(e *echo.Echo, container container.Container) { - conf := container.GetConfig() - logger := container.GetLogger() - - e.Use(SessionMiddleware(container)) - - if conf.Extension.SecurityEnabled { - if conf.Redis.Enabled { - logger.GetZapLogger().Infof("Try redis connection") - address := fmt.Sprintf("%s:%s", conf.Redis.Host, conf.Redis.Port) - store, err := redistore.NewRediStore(conf.Redis.ConnectionPoolSize, "tcp", address, "", []byte("secret")) - if err != nil { - logger.GetZapLogger().Errorf("Failure redis connection") - } - e.Use(session.Middleware(store)) - logger.GetZapLogger().Infof(fmt.Sprintf("Success redis connection, %s", address)) - } else { - e.Use(session.Middleware(sessions.NewCookieStore([]byte("secret")))) - } - e.Use(AuthenticationMiddleware(container)) - } -} - -// RequestLoggerMiddleware is middleware for logging the contents of requests. -func RequestLoggerMiddleware(container container.Container) echo.MiddlewareFunc { - return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - req := c.Request() - res := c.Response() - if err := next(c); err != nil { - c.Error(err) - } - - template := fasttemplate.New(container.GetConfig().Log.RequestLogFormat, "${", "}") - logstr := template.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { - switch tag { - case "remote_ip": - return w.Write([]byte(c.RealIP())) - case "account_name": - if account := container.GetSession().GetAccount(); account != nil { - return w.Write([]byte(account.Name)) - } - return w.Write([]byte("None")) - case "uri": - return w.Write([]byte(req.RequestURI)) - case "method": - return w.Write([]byte(req.Method)) - case "status": - return w.Write([]byte(strconv.Itoa(res.Status))) - default: - return w.Write([]byte("")) - } - }) - container.GetLogger().GetZapLogger().Infof(logstr) - return nil - } - } -} - -// ActionLoggerMiddleware is middleware for logging the start and end of controller processes. -// ref: https://echo.labstack.com/cookbook/middleware -func ActionLoggerMiddleware(container container.Container) echo.MiddlewareFunc { - return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - logger := container.GetLogger() - logger.GetZapLogger().Debugf(c.Path() + " Action Start") - if err := next(c); err != nil { - c.Error(err) - } - logger.GetZapLogger().Debugf(c.Path() + " Action End") - return nil - } - } -} - -// SessionMiddleware is a middleware for setting a context to a session. -func SessionMiddleware(container container.Container) echo.MiddlewareFunc { - return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - container.GetSession().SetContext(c) - if err := next(c); err != nil { - c.Error(err) - } - return nil - } - } -} - -// StaticContentsMiddleware is the middleware for loading the static files. -func StaticContentsMiddleware(e *echo.Echo, container container.Container, staticFile embed.FS) { - conf := container.GetConfig() - if conf.StaticContents.Enabled { - staticConfig := echomd.StaticConfig{ - Root: "resources/public", - Index: "index.html", - Browse: false, - HTML5: true, - Filesystem: http.FS(staticFile), - } - if conf.Swagger.Enabled { - staticConfig.Skipper = func(c echo.Context) bool { - return equalPath(c.Path(), []string{conf.Swagger.Path}) - } - } - e.Use(echomd.StaticWithConfig(staticConfig)) - container.GetLogger().GetZapLogger().Infof("Served the static contents.") - } -} - -// AuthenticationMiddleware is the middleware of session authentication for echo. -func AuthenticationMiddleware(container container.Container) echo.MiddlewareFunc { - return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - if !hasAuthorization(c, container) { - return c.JSON(http.StatusUnauthorized, false) - } - if err := next(c); err != nil { - c.Error(err) - } - return nil - } - } -} - -// hasAuthorization judges whether the user has the right to access the path. -func hasAuthorization(c echo.Context, container container.Container) bool { - currentPath := c.Path() - if equalPath(currentPath, container.GetConfig().Security.AuthPath) { - if equalPath(currentPath, container.GetConfig().Security.ExculdePath) { - return true - } - account := container.GetSession().GetAccount() - if account == nil { - return false - } - if account.Authority.Name == "Admin" && equalPath(currentPath, container.GetConfig().Security.AdminPath) { - _ = container.GetSession().Save() - return true - } - if account.Authority.Name == "User" && equalPath(currentPath, container.GetConfig().Security.UserPath) { - _ = container.GetSession().Save() - return true - } - return false - } - return true -} - -// equalPath judges whether a given path contains in the path list. -func equalPath(cpath string, paths []string) bool { - for i := range paths { - if regexp.MustCompile(paths[i]).Match([]byte(cpath)) { - return true - } - } - return false -} diff --git a/src/sample-golang-echo-app/migration/db_generator.go b/src/sample-golang-echo-app/migration/db_generator.go deleted file mode 100644 index 2e4e3acc46aab58abca0db85eb1dc14e483b9905..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/migration/db_generator.go +++ /dev/null @@ -1,25 +0,0 @@ -package migration - -import ( - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/model" -) - -// CreateDatabase creates the tables used in this application. -func CreateDatabase(container container.Container) { - if container.GetConfig().Database.Migration { - db := container.GetRepository() - - _ = db.DropTableIfExists(&model.Book{}) - _ = db.DropTableIfExists(&model.Category{}) - _ = db.DropTableIfExists(&model.Format{}) - _ = db.DropTableIfExists(&model.Account{}) - _ = db.DropTableIfExists(&model.Authority{}) - - _ = db.AutoMigrate(&model.Book{}) - _ = db.AutoMigrate(&model.Category{}) - _ = db.AutoMigrate(&model.Format{}) - _ = db.AutoMigrate(&model.Account{}) - _ = db.AutoMigrate(&model.Authority{}) - } -} diff --git a/src/sample-golang-echo-app/migration/master_generator.go b/src/sample-golang-echo-app/migration/master_generator.go deleted file mode 100644 index 007decdb3329d5c68a0bf923e9c61dc1dd0ae1a1..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/migration/master_generator.go +++ /dev/null @@ -1,32 +0,0 @@ -package migration - -import ( - "github.com/ybkuroki/go-webapp-sample/container" - "github.com/ybkuroki/go-webapp-sample/model" -) - -// InitMasterData creates the master data used in this application. -func InitMasterData(container container.Container) { - if container.GetConfig().Extension.MasterGenerator { - rep := container.GetRepository() - - r := model.NewAuthority("Admin") - _, _ = r.Create(rep) - a := model.NewAccountWithPlainPassword("test", "test", r.ID) - _, _ = a.Create(rep) - a = model.NewAccountWithPlainPassword("test2", "test2", r.ID) - _, _ = a.Create(rep) - - c := model.NewCategory("Technical Book") - _, _ = c.Create(rep) - c = model.NewCategory("Magazine") - _, _ = c.Create(rep) - c = model.NewCategory("Novel") - _, _ = c.Create(rep) - - f := model.NewFormat("Paper Book") - _, _ = f.Create(rep) - f = model.NewFormat("e-Book") - _, _ = f.Create(rep) - } -} diff --git a/src/sample-golang-echo-app/model/account.go b/src/sample-golang-echo-app/model/account.go deleted file mode 100644 index 6f9d8b9ca19ad5c099c288f9665525d5beb6c1d9..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/account.go +++ /dev/null @@ -1,74 +0,0 @@ -package model - -import ( - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/repository" - "golang.org/x/crypto/bcrypt" -) - -// Account defines struct of account data. -type Account struct { - ID uint `gorm:"primary_key" json:"id"` - Name string `json:"name"` - Password string `json:"-"` - AuthorityID uint `json:"authority_id"` - Authority *Authority `json:"authority"` -} - -// RecordAccount defines struct represents the record of the database. -type RecordAccount struct { - ID uint - Name string - Password string - AuthorityID uint - AuthorityName string -} - -const selectAccount = "select a.id as id, a.name as name, a.password as password," + - " r.id as authority_id, r.name as authority_name " + - " from account_master a inner join authority_master r on a.authority_id = r.id " - -// TableName returns the table name of account struct and it is used by gorm. -func (Account) TableName() string { - return "account_master" -} - -// NewAccount is constructor. -func NewAccount(name string, password string, authorityID uint) *Account { - return &Account{Name: name, Password: password, AuthorityID: authorityID} -} - -// NewAccountWithPlainPassword is constructor. And it is encoded plain text password by using bcrypt. -func NewAccountWithPlainPassword(name string, password string, authorityID uint) *Account { - hashed, _ := bcrypt.GenerateFromPassword([]byte(password), config.PasswordHashCost) - return &Account{Name: name, Password: string(hashed), AuthorityID: authorityID} -} - -// FindByName returns accounts full matched given account name. -func (a *Account) FindByName(rep repository.Repository, name string) (*Account, error) { - var account *Account - - var rec RecordAccount - rep.Raw(selectAccount+" where a.name = ?", name).Scan(&rec) - account = convertToAccount(&rec) - - return account, nil -} - -// Create persists this account data. -func (a *Account) Create(rep repository.Repository) (*Account, error) { - if err := rep.Select("name", "password", "authority_id").Create(a).Error; err != nil { - return nil, err - } - return a, nil -} - -func convertToAccount(rec *RecordAccount) *Account { - r := &Authority{ID: rec.AuthorityID, Name: rec.AuthorityName} - return &Account{ID: rec.ID, Name: rec.Name, Password: rec.Password, AuthorityID: rec.AuthorityID, Authority: r} -} - -// ToString is return string of object -func (a *Account) ToString() string { - return toString(a) -} diff --git a/src/sample-golang-echo-app/model/authority.go b/src/sample-golang-echo-app/model/authority.go deleted file mode 100644 index 3097c7ddcc06c0343c27f1afeed9d951d704aace..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/authority.go +++ /dev/null @@ -1,34 +0,0 @@ -package model - -import ( - "github.com/ybkuroki/go-webapp-sample/repository" -) - -// Authority defines struct of authority data. -type Authority struct { - ID uint `gorm:"primary_key" json:"id"` - Name string `json:"name"` -} - -// TableName returns the table name of authority struct and it is used by gorm. -func (Authority) TableName() string { - return "authority_master" -} - -// NewAuthority is constructor. -func NewAuthority(name string) *Authority { - return &Authority{Name: name} -} - -// Create persists this authority data. -func (a *Authority) Create(rep repository.Repository) (*Authority, error) { - if err := rep.Create(a).Error; err != nil { - return nil, err - } - return a, nil -} - -// ToString is return string of object -func (a *Authority) ToString() string { - return toString(a) -} diff --git a/src/sample-golang-echo-app/model/base.go b/src/sample-golang-echo-app/model/base.go deleted file mode 100644 index f4c48f6a05e11dd15be8e01414ebe19491de4846..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/base.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -import "encoding/json" - -// DomainObject defines the common interface for domain models. -type DomainObject interface { - Account | Authority | Book | Category | Format -} - -// toString returns the JSON data of the domain models. -func toString[T DomainObject](o *T) string { - var bytes []byte - var err error - if bytes, err = json.Marshal(o); err != nil { - return "" - } - return string(bytes) -} diff --git a/src/sample-golang-echo-app/model/book.go b/src/sample-golang-echo-app/model/book.go deleted file mode 100644 index f6a8358888ea7a23ff4b37d32f9612ed6dbbf836..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/book.go +++ /dev/null @@ -1,197 +0,0 @@ -package model - -import ( - "database/sql" - "errors" - "math" - - "github.com/moznion/go-optional" - "github.com/ybkuroki/go-webapp-sample/repository" - "github.com/ybkuroki/go-webapp-sample/util" - "gorm.io/gorm" -) - -// Book defines struct of book data. -type Book struct { - ID uint `gorm:"primary_key" json:"id"` - Title string `json:"title"` - Isbn string `json:"isbn"` - CategoryID uint `json:"categoryId"` - Category *Category `json:"category"` - FormatID uint `json:"formatId"` - Format *Format `json:"format"` -} - -// RecordBook defines struct represents the record of the database. -type RecordBook struct { - ID uint - Title string - Isbn string - CategoryID uint - CategoryName string - FormatID uint - FormatName string -} - -const ( - selectBook = "select b.id as id, b.title as title, b.isbn as isbn, " + - "c.id as category_id, c.name as category_name, f.id as format_id, f.name as format_name " + - "from book b inner join category_master c on c.id = b.category_id inner join format_master f on f.id = b.format_id " - findByID = " where b.id = ?" - findByTitle = " where title like ? " -) - -// TableName returns the table name of book struct and it is used by gorm. -func (Book) TableName() string { - return "book" -} - -// NewBook is constructor -func NewBook(title string, isbn string, categoryID uint, formatID uint) *Book { - return &Book{Title: title, Isbn: isbn, CategoryID: categoryID, FormatID: formatID} -} - -// FindByID returns a book full matched given book's ID. -func (b *Book) FindByID(rep repository.Repository, id uint) optional.Option[*Book] { - var rec RecordBook - args := []interface{}{id} - - createRaw(rep, selectBook+findByID, "", "", args).Scan(&rec) - return convertToBook(&rec) -} - -// FindAll returns all books of the book table. -func (b *Book) FindAll(rep repository.Repository) (*[]Book, error) { - var books []Book - var err error - - if books, err = findRows(rep, selectBook, "", "", []interface{}{}); err != nil { - return nil, err - } - return &books, nil -} - -// FindAllByPage returns the page object of all books. -func (b *Book) FindAllByPage(rep repository.Repository, page string, size string) (*Page, error) { - var books []Book - var err error - - if books, err = findRows(rep, selectBook, page, size, []interface{}{}); err != nil { - return nil, err - } - p := createPage(&books, page, size) - return p, nil -} - -// FindByTitle returns the page object of books partially matched given book title. -func (b *Book) FindByTitle(rep repository.Repository, title string, page string, size string) (*Page, error) { - var books []Book - var err error - args := []interface{}{"%" + title + "%"} - - if books, err = findRows(rep, selectBook+findByTitle, page, size, args); err != nil { - return nil, err - } - p := createPage(&books, page, size) - return p, nil -} - -func findRows(rep repository.Repository, sqlquery string, page string, size string, args []interface{}) ([]Book, error) { - var books []Book - - var rec RecordBook - var rows *sql.Rows - var err error - - if rows, err = createRaw(rep, sqlquery, page, size, args).Rows(); err != nil { - return nil, err - } - for rows.Next() { - if err = rep.ScanRows(rows, &rec); err != nil { - return nil, err - } - - opt := convertToBook(&rec) - if opt.IsNone() { - return nil, errors.New("failed to fetch data") - } - book, _ := opt.Take() - books = append(books, *book) - } - return books, nil -} - -func createRaw(rep repository.Repository, sql string, pageNum string, pageSize string, args []interface{}) *gorm.DB { - if util.IsNumeric(pageNum) && util.IsNumeric(pageSize) { - page := util.ConvertToInt(pageNum) - size := util.ConvertToInt(pageSize) - args = append(args, size) - args = append(args, page*size) - sql += " limit ? offset ? " - } - if len(args) > 0 { - return rep.Raw(sql, args...) - } - return rep.Raw(sql) -} - -func createPage(books *[]Book, page string, size string) *Page { - p := NewPage() - p.Page = util.ConvertToInt(page) - p.Size = util.ConvertToInt(size) - p.NumberOfElements = p.Size - p.TotalElements = len(*books) - if p.TotalPages = int(math.Ceil(float64(p.TotalElements) / float64(p.Size))); p.TotalPages < 0 { - p.TotalPages = 0 - } - p.Content = books - - return p -} - -// Save persists this book data. -func (b *Book) Save(rep repository.Repository) (*Book, error) { - if err := rep.Save(b).Error; err != nil { - return nil, err - } - return b, nil -} - -// Update updates this book data. -func (b *Book) Update(rep repository.Repository) (*Book, error) { - if err := rep.Model(Book{}).Where("id = ?", b.ID).Select("title", "isbn", "category_id", "format_id").Updates(b).Error; err != nil { - return nil, err - } - return b, nil -} - -// Create persists this book data. -func (b *Book) Create(rep repository.Repository) (*Book, error) { - if err := rep.Select("title", "isbn", "category_id", "format_id").Create(b).Error; err != nil { - return nil, err - } - return b, nil -} - -// Delete deletes this book data. -func (b *Book) Delete(rep repository.Repository) (*Book, error) { - if err := rep.Delete(b).Error; err != nil { - return nil, err - } - return b, nil -} - -func convertToBook(rec *RecordBook) optional.Option[*Book] { - if rec.ID == 0 { - return optional.None[*Book]() - } - c := &Category{ID: rec.CategoryID, Name: rec.CategoryName} - f := &Format{ID: rec.FormatID, Name: rec.FormatName} - return optional.Some( - &Book{ID: rec.ID, Title: rec.Title, Isbn: rec.Isbn, CategoryID: rec.CategoryID, Category: c, FormatID: rec.FormatID, Format: f}) -} - -// ToString is return string of object -func (b *Book) ToString() string { - return toString(b) -} diff --git a/src/sample-golang-echo-app/model/category.go b/src/sample-golang-echo-app/model/category.go deleted file mode 100644 index 4f4a42a6d8a96626c89fc53f2497226a0cac6987..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/category.go +++ /dev/null @@ -1,65 +0,0 @@ -package model - -import ( - "github.com/moznion/go-optional" - "github.com/ybkuroki/go-webapp-sample/repository" -) - -// Category defines struct of category data. -type Category struct { - ID uint `gorm:"primary_key" json:"id"` - Name string `validate:"required" json:"name"` -} - -// TableName returns the table name of category struct and it is used by gorm. -func (Category) TableName() string { - return "category_master" -} - -// NewCategory is constructor -func NewCategory(name string) *Category { - return &Category{Name: name} -} - -// Exist returns true if a given category exits. -func (c *Category) Exist(rep repository.Repository, id uint) (bool, error) { - var count int64 - if err := rep.Where("id = ?", id).Count(&count).Error; err != nil { - return false, err - } - if count > 0 { - return true, nil - } - return false, nil -} - -// FindByID returns a category full matched given category's ID. -func (c *Category) FindByID(rep repository.Repository, id uint) optional.Option[*Category] { - var category Category - if err := rep.Where("id = ?", id).First(&category).Error; err != nil { - return optional.None[*Category]() - } - return optional.Some(&category) -} - -// FindAll returns all categories of the category table. -func (c *Category) FindAll(rep repository.Repository) (*[]Category, error) { - var categories []Category - if err := rep.Find(&categories).Error; err != nil { - return nil, err - } - return &categories, nil -} - -// Create persists this category data. -func (c *Category) Create(rep repository.Repository) (*Category, error) { - if err := rep.Create(c).Error; err != nil { - return nil, err - } - return c, nil -} - -// ToString is return string of object -func (c *Category) ToString() string { - return toString(c) -} diff --git a/src/sample-golang-echo-app/model/dto/account.go b/src/sample-golang-echo-app/model/dto/account.go deleted file mode 100644 index 986d664781b2155dd704482bd549d58ab0f9d6bf..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/dto/account.go +++ /dev/null @@ -1,20 +0,0 @@ -package dto - -import "encoding/json" - -// LoginDto defines a data transfer object for login. -type LoginDto struct { - UserName string `json:"username"` - Password string `json:"password"` -} - -// NewLoginDto is constructor. -func NewLoginDto() *LoginDto { - return &LoginDto{} -} - -// ToString is return string of object -func (l *LoginDto) ToString() (string, error) { - bytes, err := json.Marshal(l) - return string(bytes), err -} diff --git a/src/sample-golang-echo-app/model/dto/book.go b/src/sample-golang-echo-app/model/dto/book.go deleted file mode 100644 index 3cf141bba3c6e1e8315deef5c2ed3dc40d4794dc..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/dto/book.go +++ /dev/null @@ -1,77 +0,0 @@ -package dto - -import ( - "encoding/json" - - "github.com/ybkuroki/go-webapp-sample/model" - "gopkg.in/go-playground/validator.v9" -) - -const ( - required string = "required" - max string = "max" - min string = "min" -) - -// BookDto defines a data transfer object for book. -type BookDto struct { - Title string `validate:"required,min=3,max=50" json:"title"` - Isbn string `validate:"required,min=10,max=20" json:"isbn"` - CategoryID uint `json:"categoryId"` - FormatID uint `json:"formatId"` - messages map[string]string -} - -// NewBookDto is constructor. -func NewBookDto(messages map[string]string) *BookDto { - return &BookDto{messages: messages} -} - -// Create creates a book model from this DTO. -func (b *BookDto) Create() *model.Book { - return model.NewBook(b.Title, b.Isbn, b.CategoryID, b.FormatID) -} - -// Validate performs validation check for the each item. -func (b *BookDto) Validate() map[string]string { - return validateDto(b) -} - -func validateDto(b *BookDto) map[string]string { - err := validator.New().Struct(b) - if err == nil { - return nil - } - - errors := err.(validator.ValidationErrors) - if len(errors) == 0 { - return nil - } - - return createErrorMessages(b, errors) -} - -func createErrorMessages(b *BookDto, errors validator.ValidationErrors) map[string]string { - result := make(map[string]string) - for i := range errors { - switch errors[i].StructField() { - case "Title": - switch errors[i].Tag() { - case required, min, max: - result["title"] = b.messages["ValidationErrMessageBookTitle"] - } - case "Isbn": - switch errors[i].Tag() { - case required, min, max: - result["isbn"] = b.messages["ValidationErrMessageBookISBN"] - } - } - } - return result -} - -// ToString is return string of object -func (b *BookDto) ToString() (string, error) { - bytes, err := json.Marshal(b) - return string(bytes), err -} diff --git a/src/sample-golang-echo-app/model/dto/book_test.go b/src/sample-golang-echo-app/model/dto/book_test.go deleted file mode 100644 index 25ae4664dd7d90a4fd9ef51b63dd28cd1295f0f1..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/dto/book_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package dto - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -const ( - ValidationErrMessageBookTitle string = "Please enter the title with 3 to 50 characters." - ValidationErrMessageBookISBN string = "Please enter the ISBN with 10 to 20 characters." -) - -func TestValidate_Title2Error(t *testing.T) { - dto := createBookForTitle2() - result := dto.Validate() - assert.Equal(t, ValidationErrMessageBookTitle, result["title"]) -} - -func TestValidate_Title3Success(t *testing.T) { - dto := createBookForTitle3() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Title4Success(t *testing.T) { - dto := createBookForTitle4() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Title49Success(t *testing.T) { - dto := createBookForTitle49() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Title50Success(t *testing.T) { - dto := createBookForTitle50() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Title51Error(t *testing.T) { - dto := createBookForTitle51() - result := dto.Validate() - assert.Equal(t, ValidationErrMessageBookTitle, result["title"]) -} - -func TestValidate_Isbn9Error(t *testing.T) { - dto := createBookForIsbn9() - result := dto.Validate() - assert.Equal(t, ValidationErrMessageBookISBN, result["isbn"]) -} - -func TestValidate_Isbn10Success(t *testing.T) { - dto := createBookForIsbn10() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Isbn11Success(t *testing.T) { - dto := createBookForIsbn11() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Isbn19Success(t *testing.T) { - dto := createBookForIsbn19() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Isbn20Success(t *testing.T) { - dto := createBookForIsbn20() - result := dto.Validate() - assert.Empty(t, result) -} - -func TestValidate_Isbn21Error(t *testing.T) { - dto := createBookForIsbn21() - result := dto.Validate() - assert.Equal(t, ValidationErrMessageBookISBN, result["isbn"]) -} - -func TestToString(t *testing.T) { - dto := createBookForTitle4() - result, _ := dto.ToString() - assert.Equal(t, "{\"title\":\"Test\",\"isbn\":\"123-123-123-1\",\"categoryId\":1,\"formatId\":1}", result) -} - -func createValidationMessages() map[string]string { - return map[string]string{ - "ValidationErrMessageBookTitle": "Please enter the title with 3 to 50 characters.", - "ValidationErrMessageBookISBN": "Please enter the ISBN with 10 to 20 characters."} -} - -func createBookForTitle2() *BookDto { - return &BookDto{ - Title: "Te", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForTitle3() *BookDto { - return &BookDto{ - Title: "Tes", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForTitle4() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForTitle49() *BookDto { - return &BookDto{ - Title: "Test012345Test012345Test012345Test012345Test01234", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForTitle50() *BookDto { - return &BookDto{ - Title: "Test012345Test012345Test012345Test012345Test012345", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForTitle51() *BookDto { - return &BookDto{ - Title: "Test012345Test012345Test012345Test012345Test012345T", - Isbn: "123-123-123-1", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn9() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "123456789", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn10() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "1234567890", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn19() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "1234567890123456789", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn20() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "12345678901234567890", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn21() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "123456789012345678901", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} - -func createBookForIsbn11() *BookDto { - return &BookDto{ - Title: "Test", - Isbn: "12345678901", - CategoryID: 1, - FormatID: 1, - messages: createValidationMessages(), - } -} diff --git a/src/sample-golang-echo-app/model/format.go b/src/sample-golang-echo-app/model/format.go deleted file mode 100644 index 74371a2bcd497577ba227578a28c5d0666032bc3..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/format.go +++ /dev/null @@ -1,53 +0,0 @@ -package model - -import ( - "github.com/moznion/go-optional" - "github.com/ybkuroki/go-webapp-sample/repository" -) - -// Format defines struct of format data. -type Format struct { - ID uint `gorm:"primary_key" json:"id"` - Name string `validate:"required" json:"name"` -} - -// TableName returns the table name of format struct and it is used by gorm. -func (Format) TableName() string { - return "format_master" -} - -// NewFormat is constructor -func NewFormat(name string) *Format { - return &Format{Name: name} -} - -// FindByID returns a format full matched given format's ID. -func (f *Format) FindByID(rep repository.Repository, id uint) optional.Option[*Format] { - var format Format - if err := rep.Where("id = ?", id).First(&format).Error; err != nil { - return optional.None[*Format]() - } - return optional.Some(&format) -} - -// FindAll returns all formats of the format table. -func (f *Format) FindAll(rep repository.Repository) (*[]Format, error) { - var formats []Format - if err := rep.Find(&formats).Error; err != nil { - return nil, err - } - return &formats, nil -} - -// Create persists this category data. -func (f *Format) Create(rep repository.Repository) (*Format, error) { - if err := rep.Create(f).Error; err != nil { - return nil, err - } - return f, nil -} - -// ToString is return string of object -func (f *Format) ToString() string { - return toString(f) -} diff --git a/src/sample-golang-echo-app/model/page.go b/src/sample-golang-echo-app/model/page.go deleted file mode 100644 index 5d5317d216d551e44bd5dc951a8fa55cac7d9bd0..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/model/page.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// Page defines struct of pagination data. -type Page struct { - Content *[]Book `json:"content"` - Last bool `json:"last"` - TotalElements int `json:"totalElements"` - TotalPages int `json:"totalPages"` - Size int `json:"size"` - Page int `json:"page"` - NumberOfElements int `json:"numberOfElements"` -} - -// NewPage is constructor -func NewPage() *Page { - return &Page{} -} diff --git a/src/sample-golang-echo-app/repository/repository.go b/src/sample-golang-echo-app/repository/repository.go deleted file mode 100644 index da970ddcb0fc84b0850044f5c207591e6a094414..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/repository/repository.go +++ /dev/null @@ -1,192 +0,0 @@ -package repository - -import ( - "database/sql" - "fmt" - "os" - - "github.com/ybkuroki/go-webapp-sample/config" - "github.com/ybkuroki/go-webapp-sample/logger" - "gorm.io/driver/mysql" - "gorm.io/driver/postgres" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -// Repository defines a interface for access the database. -type Repository interface { - Model(value interface{}) *gorm.DB - Select(query interface{}, args ...interface{}) *gorm.DB - Find(out interface{}, where ...interface{}) *gorm.DB - Exec(sql string, values ...interface{}) *gorm.DB - First(out interface{}, where ...interface{}) *gorm.DB - Raw(sql string, values ...interface{}) *gorm.DB - Create(value interface{}) *gorm.DB - Save(value interface{}) *gorm.DB - Updates(value interface{}) *gorm.DB - Delete(value interface{}) *gorm.DB - Where(query interface{}, args ...interface{}) *gorm.DB - Preload(column string, conditions ...interface{}) *gorm.DB - Scopes(funcs ...func(*gorm.DB) *gorm.DB) *gorm.DB - ScanRows(rows *sql.Rows, result interface{}) error - Transaction(fc func(tx Repository) error) (err error) - Close() error - DropTableIfExists(value interface{}) error - AutoMigrate(value interface{}) error -} - -// repository defines a repository for access the database. -type repository struct { - db *gorm.DB -} - -// bookRepository is a concrete repository that implements repository. -type bookRepository struct { - *repository -} - -// NewBookRepository is constructor for bookRepository. -func NewBookRepository(logger logger.Logger, conf *config.Config) Repository { - logger.GetZapLogger().Infof("Try database connection") - db, err := connectDatabase(logger, conf) - if err != nil { - logger.GetZapLogger().Errorf("Failure database connection") - os.Exit(config.ErrExitStatus) - } - logger.GetZapLogger().Infof("Success database connection, %s:%s", conf.Database.Host, conf.Database.Port) - return &bookRepository{&repository{db: db}} -} - -const ( - // SQLITE represents SQLite3 - SQLITE = "sqlite3" - // POSTGRES represents PostgreSQL - POSTGRES = "postgres" - // MYSQL represents MySQL - MYSQL = "mysql" -) - -func connectDatabase(logger logger.Logger, config *config.Config) (*gorm.DB, error) { - var dsn string - gormConfig := &gorm.Config{Logger: logger} - - if config.Database.Dialect == POSTGRES { - dsn = fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=disable", config.Database.Host, config.Database.Port, config.Database.Username, config.Database.Dbname, config.Database.Password) - return gorm.Open(postgres.Open(dsn), gormConfig) - } else if config.Database.Dialect == MYSQL { - dsn = fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local", config.Database.Username, config.Database.Password, config.Database.Host, config.Database.Dbname) - return gorm.Open(mysql.Open(dsn), gormConfig) - } - return gorm.Open(sqlite.Open(config.Database.Host), gormConfig) -} - -// Model specify the model you would like to run db operations -func (rep *repository) Model(value interface{}) *gorm.DB { - return rep.db.Model(value) -} - -// Select specify fields that you want to retrieve from database when querying, by default, will select all fields; -func (rep *repository) Select(query interface{}, args ...interface{}) *gorm.DB { - return rep.db.Select(query, args...) -} - -// Find find records that match given conditions. -func (rep *repository) Find(out interface{}, where ...interface{}) *gorm.DB { - return rep.db.Find(out, where...) -} - -// Exec exec given SQL using by gorm.DB. -func (rep *repository) Exec(sql string, values ...interface{}) *gorm.DB { - return rep.db.Exec(sql, values...) -} - -// First returns first record that match given conditions, order by primary key. -func (rep *repository) First(out interface{}, where ...interface{}) *gorm.DB { - return rep.db.First(out, where...) -} - -// Raw returns the record that executed the given SQL using gorm.DB. -func (rep *repository) Raw(sql string, values ...interface{}) *gorm.DB { - return rep.db.Raw(sql, values...) -} - -// Create insert the value into database. -func (rep *repository) Create(value interface{}) *gorm.DB { - return rep.db.Create(value) -} - -// Save update value in database, if the value doesn't have primary key, will insert it. -func (rep *repository) Save(value interface{}) *gorm.DB { - return rep.db.Save(value) -} - -// Update update value in database -func (rep *repository) Updates(value interface{}) *gorm.DB { - return rep.db.Updates(value) -} - -// Delete delete value match given conditions. -func (rep *repository) Delete(value interface{}) *gorm.DB { - return rep.db.Delete(value) -} - -// Where returns a new relation. -func (rep *repository) Where(query interface{}, args ...interface{}) *gorm.DB { - return rep.db.Where(query, args...) -} - -// Preload preload associations with given conditions. -func (rep *repository) Preload(column string, conditions ...interface{}) *gorm.DB { - return rep.db.Preload(column, conditions...) -} - -// Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically -func (rep *repository) Scopes(funcs ...func(*gorm.DB) *gorm.DB) *gorm.DB { - return rep.db.Scopes(funcs...) -} - -// ScanRows scan `*sql.Rows` to give struct -func (rep *repository) ScanRows(rows *sql.Rows, result interface{}) error { - return rep.db.ScanRows(rows, result) -} - -// Close close current db connection. If database connection is not an io.Closer, returns an error. -func (rep *repository) Close() error { - sqlDB, _ := rep.db.DB() - return sqlDB.Close() -} - -// DropTableIfExists drop table if it is exist -func (rep *repository) DropTableIfExists(value interface{}) error { - return rep.db.Migrator().DropTable(value) -} - -// AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data -func (rep *repository) AutoMigrate(value interface{}) error { - return rep.db.AutoMigrate(value) -} - -// Transaction start a transaction as a block. -// If it is failed, will rollback and return error. -// If it is sccuessed, will commit. -// ref: https://github.com/jinzhu/gorm/blob/master/main.go#L533 -func (rep *repository) Transaction(fc func(tx Repository) error) (err error) { - panicked := true - tx := rep.db.Begin() - defer func() { - if panicked || err != nil { - tx.Rollback() - } - }() - - txrep := &repository{} - txrep.db = tx - err = fc(txrep) - - if err == nil { - err = tx.Commit().Error - } - - panicked = false - return -} diff --git a/src/sample-golang-echo-app/resources/config/application.develop.yml b/src/sample-golang-echo-app/resources/config/application.develop.yml deleted file mode 100644 index 1f4c5af43ddd4d8cb9372f11378012371eeaf150..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/application.develop.yml +++ /dev/null @@ -1,36 +0,0 @@ -database: - dialect: sqlite3 - host: book.db - port: - dbname: - username: - password: - migration: true - -extension: - master_generator: true - cors_enabled: true - security_enabled: true - -log: - request_log_format: ${remote_ip} ${account_name} ${uri} ${method} ${status} - -staticcontents: - enabled: true - -swagger: - enabled: true - path: /swagger/.* - -security: - auth_path: - - /api/.* - exclude_path: - - /swagger/.* - - /api/auth/login$ - - /api/auth/logout$ - - /api/health$ - user_path: - - /api/.* - admin_path: - - /api/.* \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/config/application.docker.yml b/src/sample-golang-echo-app/resources/config/application.docker.yml deleted file mode 100644 index 62b8af7dc46289a7b90dcb04029e3d44ca585084..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/application.docker.yml +++ /dev/null @@ -1,28 +0,0 @@ -database: - dialect: postgres - host: postgres-db - port: 5432 - dbname: testdb - username: testusr - password: testusr - migration: false - -extension: - master_generator: false - cors_enabled: false - security_enabled: true - -log: - request_log_format: ${remote_ip} ${account_name} ${uri} ${method} ${status} - -security: - auth_path: - - /api/.* - exclude_path: - - /api/auth/login$ - - /api/auth/logout$ - - /api/health$ - user_path: - - /api/.* - admin_path: - - /api/.* \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/config/application.k8s.yml b/src/sample-golang-echo-app/resources/config/application.k8s.yml deleted file mode 100644 index 378e43294277426f972559f25876a94d90247193..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/application.k8s.yml +++ /dev/null @@ -1,34 +0,0 @@ -database: - dialect: postgres - host: dbserver-k8s-service - port: 5432 - dbname: testdb - username: testusr - password: testusr - migration: false - -redis: - enabled: true - connection_pool_size: 10 - host: redis-k8s-service - port: 6379 - -extension: - master_generator: false - cors_enabled: false - security_enabled: true - -log: - request_log_format: ${remote_ip} ${account_name} ${uri} ${method} ${status} - -security: - auth_path: - - /api/.* - exclude_path: - - /api/auth/login$ - - /api/auth/logout$ - - /api/health$ - user_path: - - /api/.* - admin_path: - - /api/.* \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/config/messages.properties b/src/sample-golang-echo-app/resources/config/messages.properties deleted file mode 100644 index 475ad0e14e640e314ce0f422b304b6433f52241f..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/messages.properties +++ /dev/null @@ -1,3 +0,0 @@ -# validation messages for book model -ValidationErrMessageBookTitle = Please enter the title with 3 to 50 characters. -ValidationErrMessageBookISBN = Please enter the ISBN with 10 to 20 characters. diff --git a/src/sample-golang-echo-app/resources/config/zaplogger.develop.yml b/src/sample-golang-echo-app/resources/config/zaplogger.develop.yml deleted file mode 100644 index b21670adc4722172c49d0640ffcfd99139beee17..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/zaplogger.develop.yml +++ /dev/null @@ -1,24 +0,0 @@ -zap_config: - level: "debug" - encoding: "console" - development: true - encoderConfig: - messageKey: "Msg" - levelKey: "Level" - timeKey: "Time" - nameKey: "Name" - callerKey: "Caller" - stacktraceKey: "St" - levelEncoder: "capital" - timeEncoder: "iso8601" - durationEncoder: "string" - callerEncoder: "short" - outputPaths: - - "stdout" - errorOutputPaths: - - "stdout" - -log_rotate: - maxsize: 3 - maxage: 7 - maxbackups: 7 \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/config/zaplogger.docker.yml b/src/sample-golang-echo-app/resources/config/zaplogger.docker.yml deleted file mode 100644 index 6aebbf95082790e2365101038f414afe2bf1f6cb..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/zaplogger.docker.yml +++ /dev/null @@ -1,26 +0,0 @@ -zap_config: - level: "info" - encoding: "console" - development: true - encoderConfig: - messageKey: "Msg" - levelKey: "Level" - timeKey: "Time" - nameKey: "Name" - callerKey: "Caller" - stacktraceKey: "St" - levelEncoder: "capital" - timeEncoder: "iso8601" - durationEncoder: "string" - callerEncoder: "short" - outputPaths: - - "stdout" - - "./application.log" - errorOutputPaths: - - "stderr" - - "./error.log" - -log_rotate: - maxsize: 3 - maxage: 7 - maxbackups: 7 \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/config/zaplogger.k8s.yml b/src/sample-golang-echo-app/resources/config/zaplogger.k8s.yml deleted file mode 100644 index 6aebbf95082790e2365101038f414afe2bf1f6cb..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/config/zaplogger.k8s.yml +++ /dev/null @@ -1,26 +0,0 @@ -zap_config: - level: "info" - encoding: "console" - development: true - encoderConfig: - messageKey: "Msg" - levelKey: "Level" - timeKey: "Time" - nameKey: "Name" - callerKey: "Caller" - stacktraceKey: "St" - levelEncoder: "capital" - timeEncoder: "iso8601" - durationEncoder: "string" - callerEncoder: "short" - outputPaths: - - "stdout" - - "./application.log" - errorOutputPaths: - - "stderr" - - "./error.log" - -log_rotate: - maxsize: 3 - maxage: 7 - maxbackups: 7 \ No newline at end of file diff --git a/src/sample-golang-echo-app/resources/public/css/app.750b60b0.css b/src/sample-golang-echo-app/resources/public/css/app.750b60b0.css deleted file mode 100644 index 85aa344a749c119ec9a25fa1db0976def7f052b4..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/public/css/app.750b60b0.css +++ /dev/null @@ -1,3 +0,0 @@ -.margin { - height: 70px -} diff --git a/src/sample-golang-echo-app/resources/public/favicon.ico b/src/sample-golang-echo-app/resources/public/favicon.ico deleted file mode 100644 index df36fcfb72584e00488330b560ebcf34a41c64c2..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/favicon.ico and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-192x192.png b/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-192x192.png deleted file mode 100644 index b02aa64d97167ad649e496908b35f14c603d9249..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-192x192.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-512x512.png b/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-512x512.png deleted file mode 100644 index 06088b011eccebb820b6e8de0cd244aa443208ba..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/android-chrome-512x512.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-120x120.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-120x120.png deleted file mode 100644 index 1427cf62752646ad7217df0a61aa01fdef7475d1..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-120x120.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-152x152.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-152x152.png deleted file mode 100644 index f24d454a2ecb8851bb893192b64ee09386d30e24..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-152x152.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-180x180.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-180x180.png deleted file mode 100644 index 404e192a95ccccbede087203c42b1f25f6bc6e67..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-180x180.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-60x60.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-60x60.png deleted file mode 100644 index cf10a5602e653bb126332934e2b7f34081c19a01..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-60x60.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-76x76.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-76x76.png deleted file mode 100644 index c500769e3df9d6a6f1977ace8be4e63a8095e36a..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon-76x76.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon.png b/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon.png deleted file mode 100644 index 03c0c5d5ec302ed7b0ee2c401df9427fb9d3c117..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/apple-touch-icon.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/favicon-16x16.png b/src/sample-golang-echo-app/resources/public/img/icons/favicon-16x16.png deleted file mode 100644 index 42af00963d81b8e39a30435c60ac482d1f8756e0..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/favicon-16x16.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/favicon-32x32.png b/src/sample-golang-echo-app/resources/public/img/icons/favicon-32x32.png deleted file mode 100644 index 46ca04dee251a4fa85a2891a145fbe20cc619d96..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/favicon-32x32.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/msapplication-icon-144x144.png b/src/sample-golang-echo-app/resources/public/img/icons/msapplication-icon-144x144.png deleted file mode 100644 index 7808237a18d4009501f950044f8388d13c5e1044..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/msapplication-icon-144x144.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/mstile-150x150.png b/src/sample-golang-echo-app/resources/public/img/icons/mstile-150x150.png deleted file mode 100644 index 3b37a43ae2fdef53050291d95da2e49f78cf398e..0000000000000000000000000000000000000000 Binary files a/src/sample-golang-echo-app/resources/public/img/icons/mstile-150x150.png and /dev/null differ diff --git a/src/sample-golang-echo-app/resources/public/img/icons/safari-pinned-tab.svg b/src/sample-golang-echo-app/resources/public/img/icons/safari-pinned-tab.svg deleted file mode 100644 index 732afd8eb0aa8d33d077e92bb148901b454b40a1..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/public/img/icons/safari-pinned-tab.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - diff --git a/src/sample-golang-echo-app/resources/public/index.html b/src/sample-golang-echo-app/resources/public/index.html deleted file mode 100644 index 41d99b8a4c403d2f3c7fc721f16ad36f7373da51..0000000000000000000000000000000000000000 --- a/src/sample-golang-echo-app/resources/public/index.html +++ /dev/null @@ -1 +0,0 @@ -
- Check the README.md file for instructions on how to get this - project deployed. -
-{data.note.body}
-- No note selected. Select a note on the left, or{" "} - - create a new note. - -
- ); -} diff --git a/src/sample-node-remix-app/app/routes/notes.jsx b/src/sample-node-remix-app/app/routes/notes.jsx deleted file mode 100644 index 6714941ebc11bd7591657fc8add545bf2bc6c0b9..0000000000000000000000000000000000000000 --- a/src/sample-node-remix-app/app/routes/notes.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import { json } from "@remix-run/node"; -import { Form, Link, NavLink, Outlet, useLoaderData } from "@remix-run/react"; - -import { getNoteListItems } from "~/models/note.server"; -import { requireUserId } from "~/session.server"; -import { useUser } from "~/utils"; - -export const loader = async ({ request }) => { - const userId = await requireUserId(request); - const noteListItems = await getNoteListItems({ userId }); - return json({ noteListItems }); -}; - -export default function NotesPage() { - const data = useLoaderData(); - const user = useUser(); - - return ( -{user.email}
- -No notes yet
- ) : ( -- Laravel has wonderful documentation covering every aspect of the framework. Whether you are a newcomer or have prior experience with Laravel, we recommend reading our documentation from beginning to end. -
-- Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process. -
-- Laravel News is a community driven portal and newsletter aggregating all of the latest and most important news in the Laravel ecosystem, including new package releases and tutorials. -
-You may have mistyped the address or the page may have moved.
-If you are the application owner check the logs for more information.
-Maybe you tried to change something you didn't have access to.
-If you are the application owner check the logs for more information.
-If you are the application owner check the logs for more information.
-