Skip to content

Overview

The store has a web front-end, a mobile app and an order service, and all three need product data held by the product service. How does each of them know which URL to call, what to send and what comes back? And what happens to them when the product team rewrites its service next semester? The answer to both questions is the API.

An API (Application Programming Interface) is a contract that defines how two software components communicate. It specifies what operations are available, what inputs they accept, and what outputs they return β€” without exposing the internal implementation.

In the context of microservices, APIs are the primary integration mechanism: services expose APIs, clients consume them, and teams evolve each side independently as long as the contract is respected. A stable API boundary means the implementation behind it can be completely replaced without impacting any consumer.

flowchart LR
    consumer["Client\n(mobile, browser, service)"]
    api["API\n(contract)"]:::highlighted
    impl["Implementation\n(language, DB, framework)"]

    consumer -->|"request"| api
    api -->|"response"| consumer
    api -->|"hides"| impl
    consumer -.-x|"cannot see"| impl

    classDef highlighted fill:#fcc

Learning objectives

By the end of this class you should be able to:

  • Explain why a stable API contract lets teams change and deploy services independently.
  • Compare REST, gRPC, GraphQL, WebSocket and message-based APIs, and choose one for a given interaction.
  • Design a REST resource with correct URIs, HTTP methods, status codes, error bodies and pagination.
  • Distinguish a breaking change from a backward-compatible one, and version an API when needed.
  • Document a Spring Boot service with OpenAPI and Swagger UI, and decide where the documentation may be exposed.

Roadmap

  1. This page β€” what an API contract is, why it matters, the main API styles and how RESTful an API is.
  2. REST API Design β€” resources, methods, idempotency, status codes, errors, pagination and versioning.
  3. OpenAPI & Swagger β€” describing the contract in a machine-readable document and serving it with springdoc.

Slides

Click the slides and use ← β†’ to move through them; F goes full screen and P opens the presenter view, with the notes. Open the slides in a new tab


Why APIs matter

Without a stable API With a stable API contract
Every internal change risks breaking consumers Consumers are isolated from implementation changes
Teams must coordinate every deployment Teams deploy independently
Integration errors surface at runtime Contract is testable before integration
Documentation drifts and becomes stale Contract is the single source of truth

The contract in our platform

The hands-on makes the contract tangible. In Hands-on 1, the Account microservice is split into two Maven modules:

Module Contains Who depends on it
account the contract: the AccountController interface (POST /accounts, GET /accounts/{id}…) and the DTOs AccountIn / AccountOut the implementation and every client β€” the auth service calls accounts through it, as an OpenFeign client
account-service the implementation: AccountResource, AccountService, the JPA model AccountModel and the repository nobody β€” it is private to the account team

Because the auth service (Hands-on 3) only depends on the account module, the account team can change the database, the model or the service logic freely. Only a change to AccountController, AccountIn or AccountOut is visible to others β€” and that is exactly the change that must be negotiated and, if it breaks clients, versioned (see Versioning).

Terms used in this class

  • Consumer (or client): the code that calls the API β€” a browser, a mobile app or another service.
  • Provider: the service that implements the API.
  • Endpoint: one operation of the API, identified by an HTTP method and a path, such as GET /accounts/{id}.
  • DTO (Data Transfer Object): a class whose only job is to carry data across the API boundary β€” AccountIn, AccountOut. It is deliberately different from the database entity.

Types of APIs

Style Protocol Format Typical use
REST HTTP/1.1 or HTTP/2 JSON / XML Public and internal web APIs β€” the dominant choice
gRPC HTTP/2 Protocol Buffers (binary) High-performance internal service-to-service calls
GraphQL HTTP JSON Flexible client-driven queries; Backend for Frontend (BFF) pattern
WebSocket WebSocket protocol (starts as an HTTP Upgrade, then full-duplex over TCP) Any Real-time bidirectional communication β€” chat, live feeds, collaboration
Message-based AMQP / Kafka protocol JSON / Avro Asynchronous event-driven integration between services

The same operation β€” "give me product 42" β€” looks quite different in each of the three request/response styles:

GET /products/42 HTTP/1.1
Accept: application/json

The URL identifies the resource and the HTTP method says what to do. Any HTTP client (browser, curl, Postman) can call it.

service ProductService {
  rpc GetProduct (GetProductRequest) returns (Product);
}
message GetProductRequest { string id = 1; }
message Product { string id = 1; string name = 2; double price = 3; }

The contract is a .proto file; code is generated for client and server, and messages travel as compact binary. Calling it needs a gRPC client β€” a browser cannot call it directly.

query {
  product(id: "42") { name price }
}

A single endpoint (usually POST /graphql); the client chooses the fields it wants, which avoids over-fetching on mobile screens.

How to choose. For the store's public API (browsers, mobile apps, partners), REST is the default: universal tooling, cacheable GETs, easy to debug. gRPC pays off for chatty internal calls where latency and payload size matter. GraphQL fits a front-end that composes data from many services. Messaging is the choice when the producer should not wait for the consumer β€” covered in Event-Driven Architecture.

REST maturity (Richardson Model)3

Not all HTTP APIs are equally RESTful. Leonard Richardson defined a maturity model with four levels:

Level Characteristic Example
0 β€” Swamp of POX Single endpoint for all operations POST /service?op=getOrder
1 β€” Resources Separate URIs per resource GET /orders/42
2 β€” HTTP Verbs Correct use of GET, POST, PUT, DELETE + status codes DELETE /orders/42 β†’ 204
3 β€” Hypermedia (HATEOAS) Responses include links to next possible actions "links": [{"rel": "cancel", "href": "/orders/42/cancel"}]

POX means "Plain Old XML": the HTTP request is only a tunnel for a remote procedure call. HATEOAS stands for "Hypermedia As The Engine Of Application State": the client discovers what it can do next from links in the response, as a person does when browsing a website.

Most production REST APIs operate at level 2. Level 3 is rare in practice, in internal microservices and in public APIs alike; PayPal's REST API is a well-known example that returns links with rel and href in its responses.

This course focuses on Level 2 REST and on documenting APIs with OpenAPI / Swagger.

Common pitfalls when designing an API

  • Leaking the implementation: returning the JPA entity directly exposes columns such as the password hash and ties the contract to the database schema. Use DTOs (AccountOut has no password).
  • Chatty APIs: a screen that needs ten calls to render is slow across a network; design resources around what consumers need.
  • Silent breaking changes: renaming a JSON field is invisible to the provider's own tests but breaks every consumer. Treat the contract as public β€” see Versioning.
  • RPC disguised as REST: verbs in the URL (/createOrder) put the API at Richardson level 0–1.

Topics covered

  • REST API Design


    HTTP methods, status codes, URL conventions, request and response structure, versioning, and the design principles that make APIs predictable and easy to consume.

    REST API Design

  • OpenAPI & Swagger


    Documenting APIs with the OpenAPI specification. Integrating Swagger UI into a Spring Boot service so that API documentation is always in sync with the code.

    OpenAPI & Swagger


Key takeaways

  • An API is a contract: consumers depend on it, never on the implementation behind it.
  • In the hands-on, the contract is a separate module (account: interface + DTOs) from the implementation (account-service).
  • REST over HTTP is the default for web APIs; gRPC, GraphQL, WebSocket and messaging solve specific needs.
  • Most APIs live at Richardson level 2: resources + HTTP methods + status codes. REST was defined by Roy Fielding2 on top of HTTP semantics1.
  • Never expose entities; changing a DTO is changing the contract.

Connections



  1. RFC 9110 β€” HTTP Semantics ↩

  2. FIELDING, R. T. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, UC Irvine, 2000. (Original REST definition.) ↩

  3. FOWLER, M. Richardson Maturity Model. martinfowler.com, 2010. ↩