Skip to content

Endpoints

Endpoints compose the controller layer of the application, with each endpoint being defined by its HTTP method (GET, POST, PATCH, DELETE, etc.) and its route. The purpose of an endpoint is to receive requests, validate input, invoke the necessary services, and return structured responses. This layer does not manage or maintain any active database session; instead, it delegates all data operations to the service layer.

In Atlas, each endpoint is implemented as an AWS Lambda handler wrapped by the @controller_method decorator, which provides proper formatted error handling for responses.

Initializing the functions package

Before creating endpoints, create the src/functions directory. This is where all the API's controllers will be stored.

Creating an Endpoint

To create an endpoint, follow the steps below:

  • Create a nested directory structure inside src/functions according to what the endpoint's route will look like, e.g. src/functions/manager/products/{uuid}/categories -> /manager/products/{uuid}/categories;
  • Create a Python file inside the endpoint's directory named with the intended HTTP method, e.g. "GET.py", "POST.py", etc.;
  • Inside such file, create a Lambda handler parameterized with HttpRequest and wrapped with @controller_method;

Example:

src/functions/manager/products/GET.py
import os
import sys
from typing import Dict, Any

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from .__resources__.get_response_dto import ResponseDTO, PageResponseDTO

from atlas.common import Pageable
from atlas.decorators import controller_method
from atlas.http import HttpRequest, HttpResponse

from common import Messages
from services.__di_container__ import product_service

@controller_method
def lambda_handler(req: HttpRequest) -> Dict[str, Any]:
    pageable = Pageable(
        page_number=req.query_param("page_number", int),
        page_size=req.query_param("page_size", int),
        sort=req.query_param("sort", str),
    )
    search = req.query_param("search")

    page = product_service.list_by_criteria(search=search, pageable=pageable, ret_dto_type=PageResponseDTO)

    return HttpResponse.build(200, ResponseDTO(
        message=Messages.get("PRODUCT_SUCCESSFULLY_FETCHED"),
        page=page
    ).model_dump_json())

You can read the request's data using methods from HttpRequest.

Private Resources

It's possible to create a __resources__ directory (inside the endpoints' directory) for storing local, private files used by it. The contents in __resources__ need to have names that start with the endpoint's HTTP method, e.g. post_request_dto.py, get_response_dto.py, patch_foobar.py, etc.

It's also possible to create a directory named after the HTTP method's name and store inside it all the files (with arbitrary names) used by such endpoint, e.g. __resources__/post/any_file.py.

The most common use is for storing request and response DTOs. For importing such files into the endpoint's code, you can use sys.path.append as below.

Example:

import os
import sys
from typing import Dict, Any

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from .__resources__.get_response_dto import ResponseDTO

from atlas.http import HttpRequest

@controller_method
def lambda_handler(req: HttpRequest) -> Dict[str, Any]:
    ...

Private Configuration

For setting values for endpoint-level API configuration options, create a __config__ directory (inside the endpoint's directory) for storing local, private JSON files named after the endpoint's HTTP method, e.g. GET.json, POST.json, etc. — one for each endpoint in that route that needs to have its options configured.

You can get more details on available infrastructure options here.