Self-hosted service
rasadov/EcommerceAPI avatar
rasadov/EcommerceAPI

EcommerceAPI: a Go and Python microservices sample with a GraphQL gateway

Modular e-commerce backend with a GraphQL gateway and gRPC microservices for accounts, products, orders, payments, and recommendations.

696 stars106 forksGoApache-2.0

At a glance

What is it?
EcommerceAPI is an Apache-2.0 sample e-commerce platform that splits accounts, products, orders and payments into Go services behind a gqlgen GraphQL gateway, with Kafka carrying events to a Python recommender. It suits engineers learning a microservices topology end to end, and it is a demonstration with a hardcoded payment provider and no release history.
Who is it for?
EcommerceAPI fits an engineer who wants to see a GraphQL gateway, gRPC service boundaries and a Kafka event pipeline in one runnable stack, since the compose file brings up the databases, the broker and the gateway together and the Playground lets you exercise the mutations by hand.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 103 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the sample demonstrates rather than ships

The README is explicit about the intent. This repository hosts a sample e-commerce platform demonstrating a microservices architecture using multiple Go services alongside a Python-based Recommender service. What the project sets out to demonstrate is gRPC communication between services, a Kafka-based event streaming pipeline, a unified GraphQL API gateway for clients, and Elasticsearch integration for product search.

The word sample does real work in that sentence, and it sets the correct expectations for anyone considering this code for production. What is here is a topology you can read and run, not a business system.

The services are six. Account in Go manages user accounts, authentication and authorization. Product in Go does CRUD for products and indexes product data into Elasticsearch. Order in Go handles order creation and persistence and publishes events to Kafka. Payment in Go handles payment operations and sends updates back to the order service. Recommender in Python consumes Kafka events and builds product recommendations. And the API Gateway in Go exposes a unified GraphQL API for front-end clients.

The whole ecosystem is containerized with Docker Compose, and the datastores are PostgreSQL, Elasticsearch and Kafka.

The audience is an engineer who wants to see how these five interaction patterns fit together: synchronous gRPC between services, asynchronous events through a broker, a gateway that stitches a graph together, a search index, and a model service in a second language. The author is Rauf Asadov, and the licence is Apache 2.0.

The repository layout mirrors the services exactly, with account/, product/, order/, payment/, graphql/, recommender/ and a shared pkg/ directory, plus a tests/ directory, a docker/ directory with the build files, and docker-compose.yaml at the root.

The communication map, and where the events actually flow

The Communication Overview section is the clearest part of the repository and it is worth reading line by line, because it tells you which relationships are synchronous and which are asynchronous.

Every path from the gateway goes through a gRPC client to a service, and every service reaches its own store. The API Gateway talks to an Account client that reaches the Account server, which writes to Postgres. It talks to a Product client reaching the Product server, which writes to Elasticsearch and Kafka. The Order client reaches the Order server, which writes to Postgres and Kafka, and the order service also communicates with the product service over gRPC. The Payment client reaches the Payment service, which talks to a payment provider and writes to Postgres and Kafka. And the Recommender client reaches the Recommender server in Python, which writes to a Postgres replica of the product database and to Kafka.

The event flow is the part that distinguishes this from a plain RPC split. Order and Product act as Kafka producers. The Payment service is a Kafka consumer that ingests product events and saves them at the payment provider. The Recommender service is also a Kafka consumer, ingesting order and product events and updating internal state for recommendations.

That last detail is the interesting one, because it means the recommender is not called synchronously. Nothing in the request path waits for a recommendation to be computed. The state is updated from events, and the recommendation is whatever the service has derived so far.

The tradeoff follows from that design. Eventual consistency is not a caveat here, it is the mechanism, and a product that needs a recommendation to reflect an order immediately would not get it from this topology.

The Go dependency list tells you the stack

The go.mod is worth reading because it names the exact choices, and several of them are dated in ways that matter.

The module is github.com/rasadov/EcommerceAPI on Go 1.23.4. For the GraphQL layer it uses 99designs/gqlgen at v0.17.70, along with vektah/gqlparser/v2, which is gqlgen's parser dependency, and the schema-first tooling implies a generated server rather than a hand-written resolver tree. For gRPC it uses google.golang.org/grpc at v1.71.0 and google.golang.org/protobuf at v1.36.5, and the protobuf version is the one that carries the new opaque API and the generic message API.

Persistence is GORM at v1.30.0 with the postgres driver, and lib/pq is also a direct dependency, so there is both an ORM layer and a raw driver in use. For Kafka it uses IBM/sarama at v1.45.1. The HTTP side is gin-gonic/gin at v1.10.0, and the HTTP framework is mostly there for the gateway and health endpoints rather than for the service-to-service traffic, which is gRPC.

Two entries are worth a second look. The payment integration is github.com/dodopayments/dodopayments-go at v1.52.4, which ties the sample to one named payment provider. And the search client is gopkg.in/olivere/elastic.v5 at v5.0.86, which is the Elasticsearch 5 era client, while the compose file runs an Elasticsearch image that is older still. That mismatch between a five-year-old client library and the pinned server image is exactly the kind of thing to look at before copying this into a project that will need a maintained search client.

Also present are golang-jwt/jwt/v5 for tokens, deckarep/golang-set/v2, tinrab/retry for retries, stretchr/testify for tests, and glebarez/sqlite, which suggests a lighter datastore option used in tests.

The GraphQL surface and the queries you can run

The gateway exposes a single endpoint at /graphql and uses gRPC clients for all microservices with schema stitching, which is how a client sees one graph even though the data lives in six places.

The usage section gives concrete GraphQL operations, and they show the shape of the domain model. Registration takes a name, an email and a password and returns a token, and login takes an email and a password and returns a token, which tells you the account service issues JWTs and the gateway passes them straight through.

Products are created with a name, a description and a price, and the query takes pagination with a skip and a take:

graphql
query {
  product(pagination: { skip: 0, take: 10 }) {
    id
    name
    price
  }
}

Orders take a list of products with an id and a quantity, and the selection returns the order id, the total price and the products with their names and quantities, so the order service calculates the total rather than the client.

The order creation mutation in the README is worth reading as an example of a real gateway decision:

graphql
mutation {
  createOrder(order: {
    products: [
      { id: "PRODUCT_ID", quantity: 2 }
    ]
  }) {
    id
    totalPrice
    products {
      name
      quantity
    }
  }
}

Note that the client sends only the product id and the quantity. The names in the response come from the order service calling the product service over gRPC, which is the cross-service read that the architecture diagram describes.

The Playground at /playground is where all of this is meant to be exercised, and it is the most useful part of the documentation for anyone learning the system.

Bringing the stack up with Docker Compose

The prerequisites are Docker with Docker Compose, and Git. The clone step in the README is:

bash
  git clone https://github.com/rasadov/EcommerceAPI.git
  cd ecommercemicroservices

Then the stack is started in two steps, first building the base image with docker compose build base, and then docker compose up -d --build to build and start all the services.

The compose file explains what that brings up. There is a base service built from docker/base.dockerfile with the image name rasadov/ecommerce-base:latest, and it carries a build-only profile, which is why it has to be built explicitly before the up command. There is Kafka on apache/kafka:4.1.1 in KRaft mode, with KAFKA_PROCESS_ROLES set to broker,controller and the controller quorum configured for a single node, plus Zookeeper mentioned in the startup list. There are separate PostgreSQL 14.0 instances for the account and order databases, and a product_db service that is actually an Elasticsearch image, elasticsearch-oss 6.2.4, with discovery.type set to single-node and a 1 GB heap on both sides.

That the container named product_db runs Elasticsearch is a small naming trap worth flagging, and the old Elasticsearch 6.2.4 image paired with the olivere/elastic.v5 client is consistent within the sample but dated.

The GraphQL gateway is then reachable on port 8080, both the API endpoint and the Playground, and Kafka is published on 9092 and 9093.

The compose file also hardcodes the database credentials, with the database, user and password all set to rasadov, rasadov and 123456 for the account and order databases. That is fine for a local sample and unacceptable anywhere else, so it is the first thing to change if you take this further.

The Python recommender and the replica it reads from

The Recommender service is the one component in a different language, and it is the most interesting of the six for what it says about the design.

Its responsibilities are described as a Kafka consumer that builds recommendations based on product and order events, with a tech stack of Python plus gRPC plus a PostgreSQL replica of the product database. So the recommender maintains its own state, seeded from a read replica rather than from the primary, and it keeps that state current by consuming events.

That is a defensible arrangement. Reading from a replica keeps the recommendation workload off the primary's write path, and consuming events means the recommender is not doing a query per request. The cost is that the recommendation reflects events up to the last consumed offset, and that the replica lags.

The dependency set also shows the ecosystem split. The Go side carries the payment provider client, the Kafka client and the GraphQL and gRPC generators, while the Python side carries its own gRPC client and whatever the recommender model needs. The go.mod lists python among the repository topics, which is a reminder that a language boundary in a microservices design is a real operational boundary, with two dependency trees, two test suites and two deployment pipelines.

That is the tradeoff this sample makes deliberately. A single-language stack would be simpler to build and to run, and the recommender would not be interchangeable with the rest.

Where EcommerceAPI is the wrong tool

The first and simplest case is production use. The database password is a literal 123456 in the compose file, the payment path is wired to a single named provider through its Go client, the Kafka cluster is a single-node broker with a replication factor of one, and the whole thing is started with one compose command and no resource limits, no health checks beyond the defaults, no secrets management and no migration story for the schemas. This is a teaching stack.

The second case is a team that does not want two languages and a broker. The whole point of the sample is to show the topology, so a small application that needs three services and one database should not take on Kafka, Elasticsearch, gRPC schema generation and a Python model service to get there. The infrastructure cost is not the cost of the code, it is the cost of running and observing it.

The third case is a team that has already chosen an architecture. If you have decided to use REST between services, or a single database, or a serverless function per route, this repository is a counterexample rather than a template, and copying it means taking on a topology you did not choose.

The alternative worth comparing is not another microservices sample, it is a modular monolith. A single Go service with three packages, one Postgres and one background worker covers the same product, orders and accounts use cases, and it is a fraction of the operational surface. The difference in approach is where the boundaries are drawn and what they cost you. EcommerceAPI draws them at the network, with gRPC and Kafka, which buys independent deployment and independent scaling and costs you distributed transactions, eventual consistency and two toolchains. A modular monolith draws them in the codebase, which is faster to change and harder to scale independently. The choice depends on whether your team actually needs independent deployment, and for a sample repository the honest answer is that most readers are learning the shape rather than inheriting a system.

Editorial conclusion

EcommerceAPI fits an engineer who wants to see a GraphQL gateway, gRPC service boundaries and a Kafka event pipeline in one runnable stack, since the compose file brings up the databases, the broker and the gateway together and the Playground lets you exercise the mutations by hand. It is the wrong choice as a production starting point, since the credentials in the compose file are hardcoded, the payment integration points at a single named provider, and there are no tagged releases to pin. Before adopting any of it, replace the database passwords in docker-compose.yaml, read the service directories to see which boundaries are real rather than illustrative, and confirm that a Python service and a Kafka broker fit the operational budget of the team that will maintain it.

Frequently asked questions

What services does EcommerceAPI contain?

Six: Account, Product, Order, Payment and the API Gateway in Go, plus a Recommender in Python. The gateway exposes a unified GraphQL endpoint and uses gRPC clients for all microservices with schema stitching, and the datastores are PostgreSQL, Elasticsearch and Kafka.

How do I run the EcommerceAPI stack?

Install Docker with Docker Compose and Git, clone the repository, then run docker compose build base to build the base image and docker compose up -d --build to start all services. The GraphQL endpoint is then on port 8080 at /graphql, with an interactive Playground at /playground.

How does the event flow work in EcommerceAPI?

Order and Product act as Kafka producers, while Payment and Recommender act as consumers. Payment ingests product events and saves them at the payment provider, and the Recommender ingests order and product events to update the internal state it uses for recommendations.

Which GraphQL operations does the EcommerceAPI gateway support?

The README shows register and login mutations returning a token, createProduct, a product query with skip and take pagination, and createOrder taking a list of product ids and quantities and returning the id, total price and the product names and quantities.

What licence is EcommerceAPI released under?

The project is licensed under the Apache License 2.0, with the licence file at the repository root. The repository is not archived, the last push was on 2026-07-12, and the project has no GitHub releases.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. rasadov/EcommerceAPI on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rasadov-ecommerceapi.svg)](https://hysenlabs.com/projects/rasadov-ecommerceapi)

Was this useful?