Mon code Java range des fichiers dans S3 et des données dans DynamoDB. Comment le développer et l’essayer sur ma machine, sans compte AWS, sans facture, et sans changer le code qui parle à AWS ?
Cet article présente Floci, un émulateur AWS local, avec un exemple de bout en bout : l’AWS CLI crée les ressources, une petite application Java les utilise, et la console web de Floci les montre. Je contribue au projet Floci.
Pourquoi un émulateur local
Pour essayer du code qui parle à AWS, on peut utiliser un vrai compte : il faut des identifiants, chaque appel peut coûter, et une erreur de configuration peut toucher autre chose qu’un environnement de test. Un émulateur local répond aux mêmes appels, sur la machine, sans compte et sans facture.
LocalStack est l’outil le plus connu dans ce domaine. Depuis mars 2026, d’après son propre blog, il est livré en une seule image qui demande un jeton d’authentification (« auth token »), avec une offre gratuite liée à un compte pour les particuliers et les projets open source. Floci fonctionne sans compte et sans jeton.
Floci en bref
D’après son README, Floci est « a free, open-source local AWS emulator
for development, testing, and CI », sous licence MIT. Il fait partie
d’une famille d’émulateurs : floci pour AWS (port 4566), et d’autres
pour Azure, GCP et OCI.
Tous les services AWS répondent sur http://localhost:4566. N’importe
quelle région publiée marche, et les identifiants peuvent être
n’importe quelles valeurs non vides.
Un émulateur, pas un mock
Dans un test, un mock remplace le client AWS par un faux objet. Il répond ce qu’on lui a dit de répondre. Le code ne fait aucun appel réseau, et le test vérifie surtout ce qu’on croit savoir d’AWS.
Floci est d’une autre nature : c’est un serveur qui parle le
protocole d’AWS. Le code garde le vrai client AWS (celui de l’AWS
CLI, du SDK Java, de Terraform…), qui envoie de vraies requêtes HTTP,
signées comme pour AWS. Seule l’adresse change : localhost au lieu
d’AWS.
Le README décrit son architecture :
- un routeur HTTP reçoit les requêtes au format d’AWS ;
- des services sans état (SQS, SNS, IAM, STS, KMS, Secrets Manager…) ;
- des services avec état : S3, DynamoDB et DynamoDB Streams ;
- des services qui démarrent de vrais conteneurs Docker : Lambda, RDS, ElastiCache, MSK, ECS, EC2, EKS… ;
- un stockage au choix : en mémoire, persistant, hybride, ou avec un journal d’écriture (« write-ahead log »).
Floci mesure sa compatibilité avec des suites de tests par SDK et par outil, publiées dans son dépôt : par exemple 1 326 tests pour le SDK AWS pour Java v2, 205 pour l’AWS CLI v2, 67 pour Terraform.
Démarrer Floci
La façon la plus simple est sa CLI, floci-cli (Docker doit tourner) :
floci start
floci status
Floci tourne alors dans un conteneur, et répond sur le port 4566.
Avec l’AWS CLI
floci env affiche les variables qui envoient l’AWS CLI vers Floci :
export AWS_ENDPOINT_URL='http://localhost.floci.io:4566'
export AWS_ACCESS_KEY_ID='test'
export AWS_SECRET_ACCESS_KEY='test'
export AWS_DEFAULT_REGION='us-east-1'
localhost.floci.io est un nom qui pointe vers 127.0.0.1, comme ses
sous-domaines : documents.localhost.floci.io aussi. C’est utile pour
S3, qui peut mettre le nom du bucket dans le nom d’hôte.
Je crée les ressources de l’exemple : un bucket pour les textes, une table pour les informations.
eval "$(floci env)"
aws s3 mb s3://documents
aws dynamodb create-table \
--table-name document-info \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
Pour voir que la CLI ne fait rien de spécial, l’option --debug montre
la requête :
aws s3 ls --debug
Endpoint provider result: http://localhost.floci.io:4566
Sending http request: <AWSPreparedRequest ... method=GET, url=http://localhost.floci.io:4566/,
headers={... 'Authorization': b'AWS4-HMAC-SHA256 Credential=test/..., SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=...' ...}>
Response headers: {'Content-Type': 'application/xml', ..., 'x-amz-request-id': '9f476e72-...'}
(J’ai raccourci les lignes.) La requête est signée avec SigV4
(AWS4-HMAC-SHA256), exactement comme pour AWS, et Floci répond en XML,
comme S3. Pour ne pas exporter ces variables dans chaque terminal, un
profil AWS nommé fait la même chose ; je l’explique dans
l’article sur mon poste de dev.
Avec le SDK Java
L’exemple est une petite application, publiée sur GitLab : floci-aws-local-demo. Elle range des « documents » : le texte dans S3, les informations (titre, auteur) dans DynamoDB, et la consultation renvoie les deux ensemble. Elle utilise le SDK AWS pour Java v2 ; Quarkus n’y sert que de couche web.
| Endpoint | Ce qu’il fait | Service AWS |
|---|---|---|
POST /documents (texte) | range le texte, renvoie un id | S3 |
POST /documents/{id}/info (JSON) | range le titre et l’auteur | DynamoDB |
GET /documents/{id} | renvoie les informations et le texte | DynamoDB + S3 |
GET /documents | liste les documents | DynamoDB |
C’est un exemple pédagogique : chaque classe crée son client avec des constantes visibles. Le client S3 (extrait simplifié de DocumentTextResource.java) :
private static final URI ENDPOINT = URI.create("http://localhost:4566");
private static final Region REGION = Region.US_EAST_1;
// Floci accepts any non-empty credentials.
private static final AwsBasicCredentials CREDENTIALS = AwsBasicCredentials.create("test", "test");
try (S3Client s3 = S3Client.builder()
.endpointOverride(ENDPOINT)
.region(REGION)
.credentialsProvider(StaticCredentialsProvider.create(CREDENTIALS))
.build()) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket("documents")
.key(id + ".txt")
.contentType(MediaType.TEXT_PLAIN)
.build();
s3.putObject(request, RequestBody.fromString(text));
}
C’est le client S3 qu’on utiliserait avec AWS. La seule différence est
endpointOverride : avec le vrai AWS, on retire cette ligne et on
utilise de vrais identifiants. Le client DynamoDB se crée de la même
façon, dans
DocumentInfoResource.java.
L’application se lance sur la machine, avec les versions de Java et de
Maven données par son fichier mise.toml :
mise install
mvn quarkus:dev
Puis on range un document, ses informations, et on le relit :
curl -X POST localhost:8080/documents -H 'Content-Type: text/plain' \
--data 'Floci speaks the AWS protocol on port 4566.'
{"id":"3fa7b64a-10e9-4e1e-b9d3-258a043f8122"}
curl -X POST localhost:8080/documents/3fa7b64a-10e9-4e1e-b9d3-258a043f8122/info \
-H 'Content-Type: application/json' -d '{"title":"Hello Floci","author":"Foulen Foulani"}'
curl localhost:8080/documents/3fa7b64a-10e9-4e1e-b9d3-258a043f8122
{"id":"3fa7b64a-…","title":"Hello Floci","author":"Foulen Foulani","createdAt":"2026-10-24T03:12:58.387781Z","text":"Floci speaks the AWS protocol on port 4566."}
Le titre vient de DynamoDB, le texte de S3. Un identifiant inconnu
répond 404.
Ici, l’adresse de Floci est une constante dans le code. Dans un vrai
projet, on peut la laisser hors du code : d’après le guide AWS, le SDK
pour Java 2.x lit AWS_ENDPOINT_URL, ou endpoint_url dans un profil
AWS (le SDK 1.x, non).
La console web
Floci a une console web : http://localhost:4566/_floci/ui. Elle ne
tourne pas au démarrage. À la première visite, Floci lance un conteneur
à côté de lui, qui contient la console, puis y redirige le navigateur
(ici, vers le port 4500). C’est pour cela que Floci a besoin du socket
Docker (floci start s’en charge). La console ne fait pas que montrer :
on peut aussi y créer un bucket, envoyer un fichier, ajouter un élément
dans une table ou lancer une requête PartiQL.

Le bucket documents contient le texte rangé par l’application :

Et la table document-info contient ses informations. Une requête
PartiQL les affiche en JSON :

Ce qu’il faut savoir
Un émulateur n’est pas AWS. Floci reproduit le protocole et le comportement des services, et ses suites de tests mesurent cette compatibilité ; mais pour un service précis, il vaut mieux vérifier sa place dans la liste des services et dans ces tests. Les services qui démarrent de vrais conteneurs (Lambda, RDS…) demandent Docker.
Pour aller plus loin, Floci a aussi des modules Testcontainers (Java, Node.js, Python, .NET) qui démarrent un Floci isolé pour chaque test. Tester son code avec Floci fera l’objet d’un prochain article.
Testé sur macOS avec Floci 2.3.0 (CLI 0.4.0), l’AWS CLI 2.38.5, Java 21 (Temurin 21.0.13), Quarkus 3.40.1.1 et le SDK AWS pour Java 2.46.7.
Sources : le README de Floci (présentation, architecture, console web, tests de compatibilité, Testcontainers), floci-cli, le billet de LocalStack sur la livraison de ses émulateurs, et le guide AWS sur les endpoints.