A simple microservice for notes management with REST and gRPC APIs, with support for multiple storage backends.
This project is generated using JetBrains Junie and several other AI coding agents, to evaluate agents capabilities.
Vadim Starichkov | GitHub | LinkedIn
Developed to demonstrate modern Golang development practices and patterns
- REST API for CRUD operations on notes
- gRPC API for CRUD operations on notes
- Multiple storage backends:
- In-memory storage (for development/testing)
- CouchDB storage
- MongoDB storage
- Storage-agnostic design
- Docker and Docker Compose support for easy deployment
- Docker and Docker Compose
- Go 1.24.3 or later (for local development)
To compile the application, you can use the following command:
# helps to keep unnecessary dependencies out, which can indirectly reduce size of the binary
go mod tidy
go build -ldflags="-s -w"
where:
- removes the symbol table and debug info.
-s
- removes DWARF debugging information.
-w
The easiest way to run the application is using Docker Compose, which will start both the API services and the databases:
docker-compose up -d
This will:
- Start a CouchDB instance with authentication
- Start a MongoDB instance with authentication
- Build and start two Notes API services:
- One connected to CouchDB
- One connected to MongoDB
The services will be available at:
- REST API: http://localhost:8080/api/notes
- gRPC API: localhost:8081
- CouchDB: http://localhost:5984 (admin:password)
- REST API: http://localhost:8082/api/notes
- gRPC API: localhost:8083
- MongoDB: mongodb://localhost:27017 (admin:password)
You can run just one of the services if you prefer:
# Run only the CouchDB version
docker-compose up -d couchdb notes-api-couchdb
# Run only the MongoDB version
docker-compose up -d mongodb notes-api-mongodb
To stop the services:
docker-compose down
To stop the services and remove the volumes:
docker-compose down -v
You can run the application locally with different storage backends:
The simplest way to run the application is with in-memory storage (no database required):
export STORAGE_TYPE=memory
go run main.go
To use CouchDB, you need to have CouchDB running. You can start CouchDB using Docker:
docker run -d -p 5984:5984 --name couchdb \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=password \
couchdb:3.4.3
Then, set the environment variables and run the application:
export STORAGE_TYPE=couchdb
export COUCHDB_URL=http://admin:password@localhost:5984
export COUCHDB_DB=notes
go run main.go
To use MongoDB, you need to have MongoDB running. You can start MongoDB using Docker:
docker run -d -p 27017:27017 --name mongodb \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo:7.0.20-jammy
Then, set the environment variables and run the application:
export STORAGE_TYPE=mongodb
export MONGODB_URI=mongodb://admin:password@localhost:27017
export MONGODB_DB=notes
export MONGODB_COLLECTION=notes
go run main.go
GET /api/notes
- List all notesGET /api/notes/{id}
- Get a note by IDPOST /api/notes
- Create a new notePUT /api/notes/{id}
- Update a noteDELETE /api/notes/{id}
- Delete a note
curl -X POST http://localhost:8080/api/notes \
-H "Content-Type: application/json" \
-d '{"title":"My Note","content":"This is the content of my note"}'
curl http://localhost:8080/api/notes
curl http://localhost:8080/api/notes/{id}
curl -X PUT http://localhost:8080/api/notes/{id} \
-H "Content-Type: application/json" \
-d '{"title":"Updated Title","content":"Updated content"}'
curl -X DELETE http://localhost:8080/api/notes/{id}
The application follows a clean architecture approach with a storage-agnostic design:
model
- Contains the domain model (Note)storage
- Contains the storage interface and implementations:storage.go
- Defines the NoteStorage interface and in-memory implementationcouchdb.go
- CouchDB implementation of the NoteStorage interface using the Kivik librarymongodb.go
- MongoDB implementation of the NoteStorage interface
rest
- Contains the REST API handlersgrpc
- Contains the gRPC service implementationproto
- Contains the Protocol Buffers definitions
The storage-agnostic design allows the application to work with different storage backends without changing the core business logic. The NoteStorage interface abstracts away the details of how notes are stored and retrieved, making it easy to add new storage implementations.
The project includes comprehensive tests for all components:
To run all tests:
go test ./...
To run tests for a specific package:
go test ./model
go test ./storage
go test ./rest
go test ./grpc
To run tests without external dependencies (skipping integration tests):
go test -short ./...
The tests cover:
- Model Tests: Tests for the Note model and ID generation
- Storage Tests:
- In-memory storage implementation
- MongoDB storage implementation (integration tests, requires MongoDB)
- CouchDB storage implementation (integration tests, requires CouchDB)
- REST API Tests: Tests for all REST endpoints using a mock storage
- gRPC Service Tests: Tests for all gRPC service methods using a mock storage
The integration tests for MongoDB and CouchDB are skipped when running with the -short
flag, as they require actual database instances.
This project uses GitHub Actions for continuous integration. The workflow includes:
- Building the application
- Running unit tests
- Running integration tests with code coverage reporting
- Building the Docker image
- Testing the application with Docker Compose
The workflow is defined in .github/workflows/build.yml
and runs automatically on pushes to the main branch and pull requests.
To view the latest build status and test results, click on the build status badge at the top of this README or visit the Actions tab in the GitHub repository.
The GitHub Actions workflow generates code coverage reports for the tests. These reports are available as artifacts in the workflow runs and can be downloaded to analyze test coverage.
Additionally, code coverage reports are automatically uploaded to Codecov for visualization and tracking of coverage trends over time.
The application can be configured using environment variables:
STORAGE_TYPE
- The type of storage to use: "memory", "couchdb", or "mongodb" (default: "memory")
COUCHDB_URL
- The URL of the CouchDB server (default: "http://localhost:5984")COUCHDB_DB
- The name of the CouchDB database (default: "notes")
MONGODB_URI
- The URI of the MongoDB server (default: "mongodb://localhost:27017")MONGODB_DB
- The name of the MongoDB database (default: "notes")MONGODB_COLLECTION
- The name of the MongoDB collection (default: "notes")
TemplateTasks is a developer-focused initiative by Vadim Starichkov, currently operated as sole proprietorship in Finland.
All code is released under open-source licenses. Ownership may be transferred to a registered business entity in the future.
This project is licensed under the MIT License - see the LICENSE file for details.
If you use this code in your own projects, attribution is required under the MIT License:
Based on golang-simple-notes by Vadim Starichkov, TemplateTasks
https://github.com/starichkov/golang-simple-notes
Copyright © 2025 Vadim Starichkov, TemplateTasks