Skip to main content

Overview

The GreeterService provides a greeting functionality that calls an external API via the CallerService and stores greeting records in a PostgreSQL database. This service demonstrates synchronous database writes and inter-service communication patterns. Base Path: /greeter.v1.GreeterService Authentication: Required - Bearer token via Authorization header Middleware: CORS, rate limiting, retry logic

RPCs

Greet

Generates a personalized greeting message and records it in the database. This RPC synchronously calls the CallerService to fetch external API data before responding. Endpoint: POST /greeter.v1.GreeterService/Greet Signature:
rpc Greet(GreetRequest) returns (GreetResponse)

Request

name
string
The name to greet. If empty, defaults to “World”.

Response

message
string
required
The greeting message in the format: “Hello from greeter-service!”
external_status
int32
required
HTTP status code returned from the external API call via CallerService
external_body_length
int32
required
Length of the response body from the external API call (in bytes)

Connect-Query Example

import { useQuery } from '@connectrpc/connect-query';
import { greet } from '../../../gen/greeter/v1/greeter-GreeterService_connectquery';
import { useState } from 'react';

export function GreeterDemo() {
  const [name, setName] = useState('World');

  const greetQuery = useQuery(
    greet,
    { name },
    {
      enabled: false,
    },
  );

  return (
    <div>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="name"
      />
      <button
        onClick={() => void greetQuery.refetch()}
        disabled={greetQuery.isFetching}
      >
        {greetQuery.isFetching ? 'Sending...' : 'Send Request'}
      </button>

      {greetQuery.data && (
        <pre>{JSON.stringify(greetQuery.data, null, 2)}</pre>
      )}

      {greetQuery.error && (
        <pre>{greetQuery.error.message}</pre>
      )}
    </div>
  );
}

cURL Example (h2c)

curl -X POST http://localhost:30081/greeter.v1.GreeterService/Greet \
  --http2-prior-knowledge \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Connect-Protocol-Version: 1" \
  -d '{"name": "Alice"}'

Example Response

{
  "message": "Hello Alice from greeter-service!",
  "external_status": 200,
  "external_body_length": 1234
}

Implementation Details

Database Integration

The Greet RPC performs a synchronous database write to the greetings table before returning the response:
INSERT INTO greetings (name, message, external_status) 
VALUES ($1, $2, $3)
This ensures that the greeting record is persisted before the client receives a response, guaranteeing data consistency at the cost of slightly higher latency.

Service Dependencies

  • CallerService: Called to fetch external API data (configured via EXTERNAL_API_URL environment variable, defaults to https://httpbin.org/get)
  • PostgreSQL: Stores greeting records in the greeter_db.greetings table

Error Handling

The service returns Connect RPC error codes:
  • CodeInvalidArgument: Invalid request parameters
  • CodeDeadlineExceeded: Timeout calling CallerService (2 second timeout)
  • CodeUnavailable: CallerService is unavailable
  • CodeInternal: Database or internal errors

Timeouts

  • CallerService RPC timeout: 2 seconds
  • HTTP client timeout: 3 seconds

Authentication

All requests to the GreeterService must include a valid JWT token in the Authorization header:
Authorization: Bearer <JWT_TOKEN>
The authentication is enforced at the ingress layer via Traefik middleware. Requests without valid authentication will receive a 401 Unauthorized response.

Rate Limiting

The GreeterService is protected by rate limiting middleware configured in Traefik. Excessive requests may receive a 429 Too Many Requests response.

Service Configuration

Environment VariableDefaultDescription
PORT8080Service port
CALLER_BASE_URLhttp://caller-service.microservices:8081CallerService endpoint
EXTERNAL_API_URLhttps://httpbin.org/getExternal API to call
DATABASE_URL-PostgreSQL connection string (optional)
OTEL_EXPORTER_OTLP_ENDPOINT-OpenTelemetry collector endpoint

Build docs developers (and LLMs) love