Arazzo 1.1: apa yang baru, dan apa yang berjalan hari ini
Pada 19 Mei 2026, OpenAPI Initiative merilis Arazzo 1.1.0. Arazzo adalah format OpenAPI Initiative untuk mendeskripsikan rangkaian panggilan API: login, lalu membuat pesanan, lalu membayarnya, dengan setiap langkah meneruskan nilai ke langkah berikutnya. OpenAPI menyatakan apa yang diterima dan dikembalikan satu endpoint. Arazzo menyatakan endpoint mana yang dipanggil, dalam urutan apa, dan bagaimana mengetahui apakah setiap panggilan berhasil.
Versi 1.1 adalah rilis fitur pertama sejak 1.0 pada 2024. Kami menulis workflow 1.1 terhadap API kami sendiri dan menjalankannya dengan Redocly CLI 2.62.1, yang rilis 9 Oktober. Runner-nya menerima dokumen 1.1, dan workflow sederhana membuat, membaca, mengubah, dan menghapus lulus. Dua fitur barunya lolos linter tetapi diabaikan saat workflow benar-benar dijalankan. Tulisan ini membahas apa yang berubah, workflow yang bisa Anda unduh dan jalankan, dan dua fitur yang sebaiknya dihindari dulu.
Apa yang dilakukan file Arazzo
Dokumen Arazzo menunjuk ke satu atau lebih deskripsi API, biasanya file OpenAPI, dan mendaftar workflow. Setiap workflow adalah daftar langkah. Sebuah langkah menyebut operasi lewat operationId-nya, mengisi parameter dan body request, menyatakan apa yang dihitung sebagai sukses, dan menyimpan nilai dari response untuk langkah selanjutnya.
Satu file itu berguna di tiga tempat:
- Tes. Runner menjalankan langkah-langkahnya terhadap server sungguhan dan gagal jika kriteria sukses tidak terpenuhi. Begitulah kami memakainya di bawah.
- Dokumentasi. Pembaca melihat urutan panggilan yang dibutuhkan sebuah tugas, sesuatu yang tidak bisa dinyatakan file OpenAPI.
- Agen AI. Agen yang membaca OpenAPI tahu fungsi tiap endpoint, tetapi harus menebak cara menggabungkannya. Workflow Arazzo memberitahunya.
Apa yang berubah di Arazzo 1.1
Sorotan utamanya adalah dukungan AsyncAPI, sehingga workflow bisa mencampur panggilan HTTP dengan kanal pesan. Sebagian besar perubahan lainnya membuat workflow HTTP lebih mudah ditulis. Semuanya tercantum di pengumuman rilis:
| Perubahan | Fungsinya |
|---|---|
Sumber type: asyncapi | Deskripsi sumber kini bisa berupa dokumen AsyncAPI, selain openapi dan arazzo. |
channelPath, action, correlationId, timeout | Langkah yang mengirim atau menerima pesan. action bernilai send atau receive, correlationId mencocokkan balasan dengan request-nya, dan timeout adalah batas dalam milidetik. |
dependsOn | Sebuah langkah bisa mendaftar langkah lain yang harus selesai sebelum ia mulai. Mendaftar sebuah langkah tidak menjalankannya. |
parameters pada action | Action sukses atau gagal yang memanggil workflow lain bisa meneruskan input ke workflow itu, misalnya untuk memperbarui token lalu mencoba lagi. |
| Selector Object | Mengambil nilai dari response atau input dengan JSONPath, XPath, atau JSON Pointer. Berfungsi di outputs, nilai parameter, dan body request. |
| Expression Type Object | Menetapkan versi bahasa query, seperti JSONPath menurut RFC 9535 atau XPath 3.1. Menggantikan Criterion Expression Type Object dari 1.0. |
in: querystring | Mengirim parameter sebagai seluruh query string, sesuai tambahan yang sama di OpenAPI 3.2. |
$self | URI yang mengidentifikasi dokumen, agar rujukan ke dokumen itu tidak bergantung pada lokasi file disimpan. |
Spesifikasinya juga mendapat tata bahasa lengkap untuk ekspresi runtime seperti $steps.login.outputs.token, urutan yang pasti untuk menyelesaikan deskripsi sumber, dan aturan persis kapan sebuah kondisi dianggap benar. Ini tidak menambah field, tetapi menyelesaikan kasus di mana dua runner bisa berbeda pendapat. Dukungan untuk gRPC, GraphQL, MCP, dan loop ada di roadmap versi berikutnya dan tidak ada di 1.1.
Workflow yang bisa Anda jalankan terhadap API kami
Workflow ini membuat produk di api.testingapis.com, membacanya kembali, mengubah harganya, menghapusnya, dan memeriksa bahwa produk itu sudah hilang. Ia hanya memakai endpoint gratis, jadi berjalan tanpa akun atau API key.
arazzo: 1.1.0
$self: https://testingapis.com/downloads/arazzo/products.arazzo.yaml
info:
title: Product lifecycle on testingapis.com
summary: Create a product, read it back, change its price, delete it and check that it's gone.
version: 1.0.0
sourceDescriptions:
- name: testingapis
url: ./testingapis-products.openapi.json
type: openapi
workflows:
- workflowId: product-lifecycle
inputs:
type: object
properties:
title: { type: string, default: Arazzo test product }
price: { type: number, default: 12.5 }
newPrice: { type: number, default: 9.99 }
steps:
- stepId: createProduct
operationId: Products_Create
requestBody:
contentType: application/json
payload:
title: $inputs.title
price: $inputs.price
category: electronics
successCriteria:
- condition: $statusCode == 201
outputs:
productId: $response.body#/data/id
- stepId: readProduct
operationId: Products_GetById
parameters:
- name: id
in: path
value: $steps.createProduct.outputs.productId
successCriteria:
- condition: $statusCode == 200
- context: $response.body
condition: $[?@.category == 'electronics' && @.inStock == false]
type:
type: jsonpath
version: rfc9535
onFailure:
- name: cleanUp
type: goto
stepId: deleteProduct
- stepId: changePrice
operationId: Products_Update
parameters:
- name: id
in: path
value: $steps.createProduct.outputs.productId
requestBody:
contentType: application/json
payload:
title: $inputs.title
price: $inputs.newPrice
category: electronics
successCriteria:
- condition: $statusCode == 200
- condition: $response.body#/data/price == $inputs.newPrice
onFailure:
- name: cleanUp
type: goto
stepId: deleteProduct
- stepId: deleteProduct
operationId: Products_Delete
parameters:
- name: id
in: path
value: $steps.createProduct.outputs.productId
successCriteria:
- condition: $statusCode == 200
- stepId: confirmGone
operationId: Products_GetById
parameters:
- name: id
in: path
value: $steps.createProduct.outputs.productId
successCriteria:
- condition: $statusCode == 404
outputs:
productId: $steps.createProduct.outputs.productIdUnduh bersama file OpenAPI yang ditunjuknya, taruh keduanya di satu folder, lalu jalankan. Node 22.12 atau lebih baru sudah cukup, karena npx mengambil runner-nya:
- products.arazzo.yaml
- testingapis-products.openapi.json (dokumen OpenAPI langsung kami, dipangkas menjadi endpoint produk dan echo, dengan entri
serversagar runner tahu ke mana harus mengirim request)
$ npx @redocly/cli@2.62.1 respect products.arazzo.yamlRunning workflow products.arazzo.yaml / product-lifecycle
✓ POST /api/Products - step createProduct
✓ success criteria check - $statusCode == 201
✓ status code check - $statusCode in [200, 201, 400, 500]
✓ GET /api/Products/{id} - step readProduct
✓ success criteria check - $statusCode == 200
✓ success criteria check - $[?@.category == 'electronics' && @.inStock == fal...
✓ status code check - $statusCode in [200, 404, 500]
✓ PUT /api/Products/{id} - step changePrice
✓ success criteria check - $statusCode == 200
✓ success criteria check - $response.body#/data/price == $inputs.newPrice
✓ status code check - $statusCode in [200, 404, 500]
✓ DELETE /api/Products/{id} - step deleteProduct
✓ success criteria check - $statusCode == 200
✓ status code check - $statusCode in [200, 404, 500]
✓ GET /api/Products/{id} - step confirmGone
✓ success criteria check - $statusCode == 404
✓ status code check - $statusCode in [200, 404, 500]
Workflows: 1 passed, 1 total
Steps: 5 passed, 5 total
Checks: 12 passed, 12 total
Time: 922msBeberapa bagian file ini melakukan lebih dari yang terlihat:
$response.body#/data/idadalah ekspresi runtime dengan JSON Pointer setelah#. Endpoint pembuatan kami membungkus produk baru dalam{ message, data }, jadi ID-nya ada di/data/id. Setiap langkah berikutnya membacanya sebagai$steps.createProduct.outputs.productId.- Kriteria di
readProductmemakai Expression Type Object yang baru untuk menyatakan bahwa query-nya adalah JSONPath RFC 9535. Kondisi JSONPath lulus jika filter cocok dengan setidaknya satu node, jadi$[?@.category == 'electronics' && @.inStock == false]memeriksa dua field sekaligus. Kami juga membalik nilai yang diharapkan untuk memastikan pemeriksaannya gagal saat seharusnya gagal, dan memang gagal. - Pemeriksaan ketiga di setiap langkah,
status code check, tidak ada di file Arazzo. Redocly menambahkannya dari response yang tercantum di file OpenAPI, jadi kode status yang tidak didokumentasikan API akan menggagalkan langkah meskipun kriteria Anda sendiri lulus.
Workflow-nya bersih-bersih saat sebuah langkah gagal
Produk yang dibuat di API kami dipakai bersama: siapa pun yang mendaftar produk akan melihat produk Anda sampai dihapus. Tes yang berhenti di tengah jalan akan meninggalkan sampah, jadi readProduct dan changePrice punya action onFailure yang melompat ke deleteProduct. Untuk memeriksanya, kami mengubah pemeriksaan harga agar tidak mungkin lulus:
✗ PUT /api/Products/{id} - step changePrice
✓ success criteria check - $statusCode == 200
✗ success criteria check - $response.body#/data/price == $inputs.price
✓ status code check - $statusCode in [200, 404, 500]
Running failure action cleanUp for the step changePrice
✓ DELETE /api/Products/{id} - step deleteProduct
✓ success criteria check - $statusCode == 200
✓ GET /api/Products/{id} - step confirmGone
✓ success criteria check - $statusCode == 404Workflow-nya tetap melaporkan kegagalan, tetapi produknya dihapus lebih dulu. Lakukan hal yang sama di workflow apa pun yang membuat data di lingkungan bersama.
Selector Object lolos lint tetapi tidak dijalankan
Selector Object adalah cara baru mengambil nilai dari response. Kami memakainya untuk membaca rating produk dengan JSON Pointer dan mengirimnya ke endpoint echo kami, yang mengembalikan apa pun yang diterimanya:
- stepId: getProduct
operationId: Products_GetById
parameters:
- { name: id, in: path, value: 1 }
outputs:
rating:
context: $response.body
selector: /rating/rate
type: jsonpointer
- stepId: echoIt
operationId: Echo_Echo_POST
requestBody:
contentType: application/json
payload:
rating: $steps.getProduct.outputs.ratingredocly lint meloloskan file ini. Endpoint echo seharusnya menerima {"rating": 4.3}. Inilah yang diterimanya:
{
"rating": {
"context": {
"id": 1,
"title": "Wireless Noise-Cancelling Headphones",
"price": 249.99,
...
"rating": { "rate": 4.3, "count": 127 },
"inStock": true,
"createdAt": "2025-06-12T10:30:00Z"
},
"selector": "/rating/rate",
"type": "jsonpointer"
}
}Runner menyelesaikan context menjadi seluruh body response, lalu mengirim Selector Object itu sendiri alih-alih menerapkan selektornya. Tidak ada peringatan apa pun di output. Langkahnya gagal hanya karena kami memeriksa apa yang diterima server; workflow yang hanya memeriksa 200 akan lulus sambil mengirim data yang salah.
Sampai runner menyusul, pakai bentuk 1.0. Untuk JSON Pointer, bentuk itu malah lebih pendek:
outputs:
rating: $response.body#/rating/rateParameter yang diteruskan ke workflow hilang
Contoh yang dipakai pengumuman untuk parameters adalah action gagal yang memanggil workflow pembaruan token lalu mengulang langkah. Endpoint gratis kami tidak menerbitkan token, jadi kami menguji mekanisme yang sama dengan produk yang tidak ada: action gagal memanggil workflow report yang mengirim input reason-nya ke endpoint echo.
- stepId: getMissing
operationId: Products_GetById
parameters:
- { name: id, in: path, value: 99999 }
successCriteria:
- condition: $statusCode == 200
onFailure:
- name: reportAndRetry
type: retry
retryLimit: 1
workflowId: report
parameters:
- name: reason
value: not foundRunner memang memanggil workflow report lalu mengulang langkahnya, sesuai urutan yang dijelaskan spesifikasi. Tetapi endpoint echo menerima objek kosong:
"contentType": "application/json",
"contentLength": 2,
"body": "{}",
"json": {}reason tidak pernah tiba. Menjalankan report sendiri dengan --input reason=... berfungsi, jadi masalahnya ada pada penerusan parameters dari action. Untuk pembaruan token, artinya panggilan pembaruan terkirim tanpa refresh token.
Apa yang berjalan di Redocly CLI 2.62.1
| Fitur Arazzo 1.1 | Lint | Eksekusi |
|---|---|---|
arazzo: 1.1.0 | Diterima | Berjalan |
$self | Diterima | Diterima; tidak ada yang bisa diamati saat eksekusi |
| Expression Type Object | Diterima | Berjalan, dan gagal saat seharusnya gagal |
dependsOn | Diterima | Diterima; langkah tetap berjalan berurutan |
| Selector Object | Diterima | Tidak diterapkan: objeknya dikirim sebagai data |
parameters pada action | Diterima | Workflow berjalan, input-nya kosong |
| Langkah AsyncAPI | Belum diuji | Belum diuji |
Kami tidak menemukan entri changelog Redocly yang mengklaim dukungan Arazzo 1.1, jadi mungkin ini memang fitur yang belum dibuat. Alat lain yang tercantum di repositori Arazzo mungkin berperilaku berbeda, dan kami hanya menguji Redocly.
Menulis workflow 1.1 sekarang
- Pakai
arazzo: 1.1.0dan fitur yang berjalan: Expression Type Object,$self, dandependsOn. - Baca nilai response dengan ekspresi runtime seperti
$response.body#/data/id, bukan Selector Object. - Tangani pembaruan token dengan login ulang di sebuah langkah, bukan lewat
parameterspada action gagal. - Periksa apa yang diterima server, bukan hanya kode status. Lint yang lulus maupun
200tidak menangkap satu pun masalah di tulisan ini. Endpoint echo kami yang menangkapnya. - Kunci versi runner, seperti yang kami lakukan dengan
@redocly/cli@2.62.1, agar pembaruan runner tidak mengubah hasil Anda tanpa commit.
Jika workflow Anda menguji siklus membuat, membaca, mengubah, dan menghapus, pelajaran pengujian CRUD kami membahas pemeriksaan yang dibutuhkan setiap langkah. Membaca spesifikasi OpenAPI (dalam bahasa Inggris) menjelaskan nilai operationId yang dirujuk workflow, dan dokumentasi API produk mendaftar setiap field yang disentuh workflow di atas.