Allegro REST API Design Guidelines

repository·master·Indexed 41 days ago

https://github.com/allegro/restapi-guideline

A standardized framework for designing and consuming RESTful APIs within the Allegro ecosystem. It covers conventions for resource naming, UUID identification, media-type based versioning (e.g., application/vnd.allegro.public.v1+json), URI path nesting, User-Agent requirements, and standard HTTP status codes. The guidelines also specify formats for ISO8601 dates, ISO 3166 country codes, ISO 4217 currencies, and the use of dryRun parameters for request validation.

Tokens
16K
Snippets
53
Records
76
Agent score
49%

What's inside Allegro REST API Design Guidelines

  1. Overview of Allegro REST API Design Guidelines

    master

    The Allegro REST API Design Guidelines provide a standard for implementing consistent REST APIs across Allegro's micro-services ecosystem. These guidelines are intended for two primary groups:

    1. API Designers: Developers creating micro-services that expose resources to the Allegro platform.
    2. API Consumers: Developers building applications (Mobile, Web, or third-party) that consume Allegro APIs.

    The goal is to ensure consistency between individual micro-services and the broader Allegro Public REST API, facilitating a positive Developer Experience (DX).

  2. Format dates and times using ISO8601 and UTC

    master

    All date and time values must be accepted and returned in UTC only.

    For full date and time, use the ISO8601 string format: yyyy-MM-dd'T'HH:mm:ss.SSSZ.

    If you only need to represent a time without a date, use the format HH:mm:ss.SSS without any time zone information. Clients should present this value exactly as received. If a specific time zone is required for presentation, use a full UTC date and time instead.

    {
      // Full date and time
      "createdAt": "2012-01-01T12:00:00.000Z",
      "updatedAt": "2012-01-01T13:00:00.000Z"
    }
    
    // Time without date
    {
      "from": "08:00:00.000",
      "to": "16:00:00.000"
    }
  3. Naming and structuring API resources

    master

    When designing or consuming resources, follow these naming and path conventions:

    • Resource Names: Use plural versions of resource names (e.g., /users, /offers, /shipments).
    • Path Formatting: Use lowercase and dash-separated names (e.g., /general-deliveries, /application-configurations).
    • Identification: Use UUIDs as lowercase strings in 8-4-4-4-12 format (e.g., 01234567-89ab-cdef-0123-456789abcdef). Avoid auto-incrementing IDs.
    • Nesting: Minimize nesting depth. Instead of deeply nested paths like /users/{userId}/offers/{offerId}/shipments/{shipmentId}, prefer locating resources at the root or using nesting only to indicate scoped collections (e.g., /offers/{offerId}/shipments).
  4. HATEOAS support policy

    master

    Allegro does not use or support HATEOAS (Hypermedia as the Engine of Application State) in its REST API design.

    While HATEOAS principles suggest that interaction with an endpoint should be defined via metadata within the output representation (allowing clients to discover available actions and state transitions via URLs), Allegro's design philosophy prioritizes the fact that API integration logic is typically determined at development time rather than at runtime.

    Implementing HATEOAS would require significant changes to client-side logic (such as mobile applications), necessitating that URIs be included in domain model objects or that controller contracts be updated to include URIs alongside objects.

  5. Represent countries and languages

    master

    Country Codes

    Use ISO 3166 Alpha-2 codes for country properties. These must be 2 letters and always upper-cased (e.g., PL, GB).

    Language Tags

    Use RFC 1766 (or the updated RFC 5646) language tags. These combine ISO 3166 country codes and ISO 639 language names (e.g., en-GB).

    Localized Messages via Accept-Language

    To receive localized user messages (including error messages), clients must set the Accept-Language header. Supported formats include:

    • en-* (e.g., en-GB, en-US)
    • pl-PL

    If the header is omitted or contains an unsupported value, the service should fallback to en-US.

    {
        "address" : {
            "city" : "Poznań",
            "countryCode": "PL"
        },
        "user" : {
            "prefferedLanguage": "en-GB"
        }
    }
  6. Minimize resource nesting in URI paths

    master

    Avoid deeply nested paths like /users/{userId}/offers/{offerId}/shipments/{shipmentId}. Instead, prefer locating resources at the root path and using nesting only to indicate scoped collections. This improves scalability and simplifies resource access.

    Recommended pattern:

    • /users/{userId}
    • /users/{userId}/offers
    • /offers/{offerId}
    • /offers/{offerId}/shipments
    • /shipments/{shipmentId}
    // Avoid this:
    /users/{userId}/offers/{offerId}/shipments/{shipmentId}
    
    // Prefer this:
    /users/{userId}
    /users/{userId}/offers
    /offers/{offerId}
    /offers/{offerId}/shipments
    /shipments/{shipmentId}
  7. Implement complex operations using the Command Pattern

    master

    For non-trivial operations that modify multiple fields or require complex input (e.g., renewing an offer), do not use PUT or PATCH on the main resource to trigger side effects. Instead, use the Command Pattern.

    How it works

    1. Create a sub-resource for commands under the business resource: /resource/{id}/{command-type}-commands.
    2. Execute the command using PUT with a client-generated UUID in the URI. This ensures idempotency (the operation executes only once even if the request is retried).
    3. Handle Asynchronicity: The server returns 201 Created immediately and executes the logic asynchronously. You can then poll the command URI to check the status.

    Benefits

    • Verbose declaration of complex operations.
    • Standard mechanism to trace asynchronous status.
    • Idempotent execution via client-side UUIDs.
    # 1. Adding the command (Idempotent via UUID in URI)
    curl -X PUT https://api.allegro.pl/offers/6546456/renew-commands/23453425-34253245-3453454-345345 \
         -H "Content-Type: application/vnd.allegro.public.v1+json" \
         -d '{
        "fromDate" : "2015-08-30T17:00:00.000Z",
        "duration" : "P7D"
    }'
    
    # 2. Checking execution status
    curl -X GET https://api.allegro.pl/offers/6546456/renew-commands/23453425-34253245-3453454-345345 \
         -H "Accept: application/vnd.allegro.public.v1+json"
  8. Multi-step patterns for complex changes

    master

    To minimize disruption, complex changes are often split into smaller, safer steps. If you see multiple related changes appearing, they likely follow these patterns:

    Endpoint Renaming

    1. New endpoint is introduced.
    2. Old endpoint is removed.

    Response Body Field Renaming

    1. New field is introduced.
    2. Old field is removed.

    Request Body Field Renaming

    1. New optional field is introduced.
    2. New optional field is made mandatory (Tightening input constraint).
    3. Old field is made optional (Releasing input constraint).
    4. Old field is removed.

    Adding Mandatory Elements (Query param, request body field, or header)

    1. New optional element is added.
    2. Optional element is made required (Tightening input constraint).
  9. Avoid these API antipatterns

    master

    When designing or consuming Allegro APIs, avoid these common mistakes:

    • Using POST for commands: POST is not idempotent. Use PUT with a client-generated UUID in the URI to ensure business logic executes only once.
    • Sending UUIDs in headers: This is incompatible with REST and the HTTP RFC (non-standard headers are deprecated). Put the UUID in the URI instead.
    • Using picture: Always use image.
    • Using metadata: Avoid this key; move information to the parent entity.
    • Using page or pageIndex: Always use offset for pagination.
    • HATEOAS: Allegro does not use or support HATEOAS.
  10. Naming convention for public API endpoints

    master
    All public API endpoint names must be nouns. To handle custom operations that cannot be expressed using standard HTTP methods (like GET or DELETE on a resource), you must use one of three specific patterns: the Query Pattern, the Synchronous Command Pattern, or the Asynchronous Command Pattern. This ensures compliance with the Richardson Maturity Model and RFC-9110.
  11. How advanced filtering (search) works

    master

    For complex queries involving many parameters or deep nested structures, use the advanced filtering pattern involving a dedicated search resource (conventionally named /*-searches).

    The Workflow:

    1. Create a search ID: Send a POST request with the query body to the search resource (e.g., /product-searches). The server returns a search ID in the Location header (status 201 Created).
    2. Get the collection: Use the returned search.id as a query parameter on the base resource (e.g., /products?search.id=...) to retrieve the filtered entities.
    3. Get search data: Call the search resource directly (e.g., /product-searches/{id}) to retrieve the metadata/data associated with that search.

    Important Notes:

    • Search resources should follow the /*-searches naming convention (e.g., /product-searches for /products).
    • You cannot override filters for an existing ID; you must create a new search resource.
    • Search resources should be versioned alongside the base resource to maintain compatibility.
    # 1. Create search
    curl -X POST https://api.allegro.pl/product-searches -H "Accept: application/vnd.allegro.public.v1+json" -d '{"limit": 100, "offset": 150}'
    
    # 2. Use search.id to get products
    curl -X GET "https://api.allegro.pl/products?search.id=4be770c3-4967-6805-8f13-0457dc8ed446&sort=-parameterGroups.name" -H "Accept: application/vnd.allegro.public.v1+json"
  12. Use the Synchronous Command Pattern for immediate operations

    master

    The Synchronous Command Pattern is used for custom operations that cannot be expressed by a noun and an HTTP method, where the client expects an immediate response after the operation completes.

    Key Characteristics:

    • Method: Always uses POST.
    • Suffix: The endpoint name must end with -commands.
    • Idempotency: The request may optionally include an id attribute to ensure idempotency.
    • Structure: Request and response bodies have no fixed structure.

    Example: To modify multiple offer prices in a single call, use POST /modify-offer-prices-commands.

    // POST /modify-offer-prices-commands
    {
      "changeType": "INCREASE",
      "modificationValue": 15,
      "modificationUnit": "PERCENTAGE",
      "includedOffers": [
        "12345",
        "45678",
        "56789"
      ]
    }