Bagikan melalui


Mulai menggunakan NSwag dan ASP.NET Core

Oleh Christoph Nienaber, Rico Suter, dan Dave Brock

Melihat atau mengunduh kode sampel (cara mengunduh)

NSwag menawarkan kemampuan berikut:

  • Kemampuan untuk menggunakan UI Swagger dan generator Swagger.
  • Kemampuan pembuatan kode yang fleksibel.

Dengan NSwag, Anda tidak memerlukan API yang ada—Anda dapat menggunakan API pihak ketiga yang menggabungkan Swagger dan menghasilkan implementasi klien. NSwag memungkinkan Anda mempercepat siklus pengembangan dan dengan mudah beradaptasi dengan perubahan API.

Penginstalan paket

Instal NSwag ke:

  • Hasilkan spesifikasi Swagger untuk API web yang diimplementasikan.
  • Layani antarmuka pengguna Swagger untuk menelusuri dan menguji API web.
  • Layani Redoc untuk menambahkan dokumentasi API untuk API Web.

Untuk menggunakan middleware NSwag ASP.NET Core, instal paket NSwag.AspNetCore NuGet. Paket ini berisi middleware untuk menghasilkan dan melayani spesifikasi Swagger, antarmuka pengguna Swagger (v2 dan v3), dan UI ReDoc. NSwag 14 hanya mendukung v3 dari spesifikasi UI Swagger.

Gunakan salah satu pendekatan berikut untuk menginstal paket NSwag NuGet:

  • Dari jendela Package Manager Console :

    • Buka Lihat>Konsol Pengelola Paket Windows Lainnya>

    • Navigasikan ke direktori tempat NSwagSample.csproj file ada

    • Jalankan perintah berikut:

      Install-Package NSwag.AspNetCore
      
  • Dari dialog Kelola Paket NuGet:

    • Klik kanan proyek di Penjelajah Solusi> Kelola Paket NuGet
    • Atur Sumber paket ke "nuget.org"
    • Masukkan "NSwag.AspNetCore" di kotak pencarian
    • Pilih paket "NSwag.AspNetCore" dari tab Telusuri dan klik Instal

Menambahkan dan mengonfigurasi middleware Swagger

Tambahkan dan konfigurasikan Swagger di aplikasi ASP.NET Core Anda dengan melakukan langkah-langkah berikut:

  • Tambahkan generator OpenApi ke kumpulan layanan di Program.cs:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApiDocument();
  • Aktifkan middleware untuk melayani spesifikasi OpenApi yang dihasilkan, antarmuka pengguna Swagger, dan UI Redoc, juga di Program.cs:
if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI Protected by if (env.IsDevelopment())
}
  • Luncurkan aplikasi. Navigasi ke:
    • http://localhost:<port>/swagger untuk melihat UI Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json untuk melihat spesifikasi Swagger.

Pembuatan kode

Anda dapat memanfaatkan kemampuan pembuatan kode NSwag dengan memilih salah satu opsi berikut:

  • NSwagStudio: Aplikasi desktop Windows untuk menghasilkan kode klien API di C# atau TypeScript.
  • Paket NSwag.CodeGeneration.CSharp atau NSwag.CodeGeneration.TypeScript NuGet untuk pembuatan kode di dalam proyek Anda.
  • NSwag dari baris perintah.
  • Paket NSwag.MSBuild NuGet.
  • Layanan Terhubung Unchase OpenAPI (Swagger): Layanan Terhubung Visual Studio untuk menghasilkan kode klien API di C# atau TypeScript. Juga menghasilkan pengontrol C# untuk layanan OpenAPI dengan NSwag.

Hasilkan kode dengan NSwagStudio

  • Instal NSwagStudio dengan mengikuti instruksi di repositori GitHub NSwagStudio. Pada halaman rilis NSwag, Anda dapat mengunduh versi xcopy yang dapat dimulai tanpa hak istimewa penginstalan dan admin.
  • Luncurkan NSwagStudio dan masukkan swagger.json URL file di kotak teks URL Spesifikasi Swagger. Contohnya,http://localhost:5232/swagger/v1/swagger.json.
  • Klik tombol Buat Salinan lokal untuk menghasilkan representasi JSON dari spesifikasi Swagger Anda.

NSwag Studio mengimpor spesifikasi dan mengekspor Klien CSharp.

  • Di area Output, klik kotak centang Klien CSharp. Bergantung pada proyek, Anda juga dapat memilih TypeScript Client atau CSharp Web API Controller. Jika Anda memilih CSharp Web API Controller, spesifikasi layanan membangun kembali layanan, berfungsi sebagai generasi terbalik.
  • Klik Hasilkan Output untuk menghasilkan implementasi klien C# lengkap dari proyek TodoApi.NSwag . Untuk melihat kode klien yang dihasilkan, klik tab Klien CSharp:
namespace MyNamespace
{
    using System = global::System;

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.1.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
    public partial class TodoClient
    {
    #pragma warning disable 8618 // Set by constructor via BaseUrl property
        private string _baseUrl;
    #pragma warning restore 8618 // Set by constructor via BaseUrl property
        private System.Net.Http.HttpClient _httpClient;
        private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            BaseUrl = "http://localhost:5232";
            _httpClient = httpClient;
        }

        private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
        {
            var settings = new Newtonsoft.Json.JsonSerializerSettings();
            UpdateJsonSerializerSettings(settings);
            return settings;
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set
            {
                _baseUrl = value;
                if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/"))
                    _baseUrl += '/';
            }
        }
        // code omitted for brevity

Tip

Kode klien C# dihasilkan berdasarkan pilihan di tab Pengaturan . Ubah pengaturan untuk melakukan tugas seperti penggantian nama namespace default dan pembuatan metode sinkron.

  • Salin kode C# yang dihasilkan ke dalam file di proyek klien yang akan menggunakan API.
  • Mulai gunakan API web:
var todoClient = new TodoClient(new HttpClient());

// Gets all to-dos from the API
var allTodos = await todoClient.GetAsync();

// Create a new TodoItem, and save it via the API.
await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Mengkustomisasi dokumentasi API

OpenApi menyediakan opsi untuk mendokumentasikan model objek untuk memudahkan konsumsi API web.

Info dan deskripsi API

Di Program.cs, perbarui AddOpenApiDocument untuk mengonfigurasi info dokumen API Web dan menyertakan informasi selengkapnya seperti penulis, lisensi, dan deskripsi. NSwag Impor namespace terlebih dahulu untuk menggunakan OpenApi kelas.

using NSwag;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApiDocument(options => {
     options.PostProcess = document =>
     {
         document.Info = new OpenApiInfo
         {
             Version = "v1",
             Title = "ToDo API",
             Description = "An ASP.NET Core Web API for managing ToDo items",
             TermsOfService = "https://example.com/terms",
             Contact = new OpenApiContact
             {
                 Name = "Example Contact",
                 Url = "https://example.com/contact"
             },
             License = new OpenApiLicense
             {
                 Name = "Example License",
                 Url = "https://example.com/license"
             }
         };
     };
});

UI Swagger menampilkan informasi versi:

Antarmuka pengguna Swagger dengan informasi versi.

Komentar XML

Untuk mengaktifkan komentar XML, lakukan langkah-langkah berikut:

  • Klik kanan proyek di Penjelajah Solusi dan pilih Edit <project_name>.csproj.
  • Tambahkan baris yang disorot secara manual ke .csproj file:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

Mengaktifkan komentar XML menyediakan informasi debug untuk jenis publik dan anggota yang tidak terdokumentasi. Jenis dan anggota yang tidak terdokumentasi ditunjukkan oleh pesan peringatan. Misalnya, pesan berikut menunjukkan pelanggaran kode peringatan 1591:

warning CS1591: Missing XML comment for publicly visible type or member 'TodoContext'

Untuk menyembunyikan peringatan di seluruh proyek, tentukan daftar kode peringatan yang dibatasi titik koma untuk diabaikan dalam file proyek. Menambahkan kode peringatan untuk $(NoWarn); menerapkan nilai default C# juga.

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Untuk menekan peringatan hanya untuk anggota tertentu, sertakan kode dalam petunjuk praprosedur peringatan #pragma. Pendekatan ini berguna untuk kode yang tidak boleh diekspos melalui dokumen API. Dalam contoh berikut, kode peringatan CS1591 diabaikan untuk seluruh TodoContext kelas. Penerapan kode peringatan dipulihkan pada penutupan definisi kelas. Tentukan beberapa kode peringatan dengan daftar yang dibatasi koma.

namespace NSwagSample.Models;

#pragma warning disable CS1591
public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options) : base(options) { }

    public DbSet<TodoItem> TodoItems => Set<TodoItem>();
}
#pragma warning restore CS1591

Anotasi data

Tandai model dengan atribut, yang ditemukan di System.ComponentModel.DataAnnotations namespace layanan, untuk membantu mendorong komponen antarmuka pengguna Swagger.

[Required] Tambahkan atribut ke Name properti TodoItem kelas :

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace NSwagSample.Models;

public class TodoItem
{
    public long Id { get; set; }

    [Required]
    public string Name { get; set; } = null!;

    [DefaultValue(false)]
    public bool IsComplete { get; set; }
}

Kehadiran atribut ini mengubah perilaku UI dan mengubah skema JSON yang mendasar:

"TodoItem": {
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64"
    },
    "name": {
      "type": "string",
      "minLength": 1
    },
    "isComplete": {
      "type": "boolean",
      "default": false
    }
  }
}

Ketika penggunaan anotasi data di API web meningkat, halaman bantuan UI dan API menjadi lebih deskriptif dan berguna.

Menjelaskan jenis respons

Pengembang yang menggunakan API web paling peduli dengan apa yang dikembalikan—khususnya jenis respons dan kode kesalahan (jika tidak standar). Jenis respons dan kode kesalahan ditandai dalam komentar XML dan anotasi data.

Tindakan mengembalikan Create kode status HTTP 201 saat berhasil. Kode status HTTP 400 dikembalikan ketika isi permintaan yang diposting adalah null. Tanpa dokumentasi yang tepat di antarmuka pengguna Swagger, konsumen tidak memiliki pengetahuan tentang hasil yang diharapkan ini. Perbaiki masalah tersebut dengan menambahkan baris yang disorot dalam contoh berikut:

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = item.Id }, item);
}

UI Swagger sekarang dengan jelas mendokumentasikan kode respons HTTP yang diharapkan (dan komentar XML juga ditampilkan):

UI Swagger memperlihatkan deskripsi Kelas Respons POST 'Mengembalikan item Todo yang baru dibuat' dan '400 - Jika item null' untuk kode status dan alasan di bawah Pesan Respons.

Konvensi dapat digunakan sebagai alternatif untuk mendekorasi tindakan individu secara eksplisit dengan [ProducesResponseType]. Untuk informasi selengkapnya, lihat Menggunakan konvensi API web.

Redoc

Redoc adalah alternatif untuk UI Swagger. Ini mirip karena juga menyediakan halaman dokumentasi untuk API Web menggunakan spesifikasi OpenAPI. Perbedaannya adalah bahwa Redoc UI lebih berfokus pada dokumentasi, dan tidak menyediakan UI interaktif untuk menguji API.

Untuk mengaktifkan Redoc, tambahkan middleware-nya ke Program.cs:

if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI is called only in Development.
    
    // Add ReDoc UI to interact with the document
    // Available at: http://localhost:<port>/redoc
    app.UseReDoc(options =>
    {
        options.Path = "/redoc";
    });
}

Jalankan aplikasi dan navigasi ke untuk http://localhost:<port>/redoc melihat UI Redoc:

Dokumentasi Redoc untuk Api Sampel.

Oleh Christoph Nienaber, Rico Suter, dan Dave Brock

Melihat atau mengunduh kode sampel (cara mengunduh)

NSwag menawarkan kemampuan berikut:

  • Kemampuan untuk menggunakan UI Swagger dan generator Swagger.
  • Kemampuan pembuatan kode yang fleksibel.

Dengan NSwag, Anda tidak memerlukan API yang ada—Anda dapat menggunakan API pihak ketiga yang menggabungkan Swagger dan menghasilkan implementasi klien. NSwag memungkinkan Anda mempercepat siklus pengembangan dan dengan mudah beradaptasi dengan perubahan API.

Mendaftarkan middleware NSwag

Daftarkan middleware NSwag ke:

  • Hasilkan spesifikasi Swagger untuk API web yang diimplementasikan.
  • Layani antarmuka pengguna Swagger untuk menelusuri dan menguji API web.

Untuk menggunakan middleware NSwag ASP.NET Core, instal paket NSwag.AspNetCore NuGet. Paket ini berisi middleware untuk menghasilkan dan melayani spesifikasi Swagger, antarmuka pengguna Swagger (v2 dan v3), dan UI ReDoc.

Gunakan salah satu pendekatan berikut untuk menginstal paket NSwag NuGet:

  • Dari jendela Package Manager Console :

    • Buka Lihat>Konsol Pengelola Paket Windows Lainnya>

    • Navigasikan ke direktori tempat TodoApi.csproj file ada

    • Jalankan perintah berikut:

      Install-Package NSwag.AspNetCore
      
  • Dari dialog Kelola Paket NuGet:

    • Klik kanan proyek di Penjelajah Solusi> Kelola Paket NuGet
    • Atur Sumber paket ke "nuget.org"
    • Masukkan "NSwag.AspNetCore" di kotak pencarian
    • Pilih paket "NSwag.AspNetCore" dari tab Telusuri dan klik Instal

Menambahkan dan mengonfigurasi middleware Swagger

Tambahkan dan konfigurasikan Swagger di aplikasi ASP.NET Core Anda dengan melakukan langkah-langkah berikut:

  • Dalam metode ini Startup.ConfigureServices , daftarkan layanan Swagger yang diperlukan:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<TodoContext>(opt =>
        opt.UseInMemoryDatabase("TodoList"));
    services.AddMvc();

    // Register the Swagger services
    services.AddSwaggerDocument();
}
  • Dalam metode ini Startup.Configure , aktifkan middleware untuk melayani spesifikasi Swagger yang dihasilkan dan antarmuka pengguna Swagger:
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();

    // Register the Swagger generator and the Swagger UI middlewares
    app.UseOpenApi();
    app.UseOpenApi();
    if (env.IsDevelopment())
    {
        app.UseSwaggerUi3();
    }
    app.UseMvc();
}
  • Luncurkan aplikasi. Navigasi ke:
    • http://localhost:<port>/swagger untuk melihat UI Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json untuk melihat spesifikasi Swagger.

Pembuatan kode

Anda dapat memanfaatkan kemampuan pembuatan kode NSwag dengan memilih salah satu opsi berikut:

  • NSwagStudio: Aplikasi desktop Windows untuk menghasilkan kode klien API di C# atau TypeScript.
  • Paket NSwag.CodeGeneration.CSharp atau NSwag.CodeGeneration.TypeScript NuGet untuk pembuatan kode di dalam proyek Anda.
  • NSwag dari baris perintah.
  • Paket NSwag.MSBuild NuGet.
  • Layanan Terhubung Unchase OpenAPI (Swagger): Layanan Terhubung Visual Studio untuk menghasilkan kode klien API di C# atau TypeScript. Juga menghasilkan pengontrol C# untuk layanan OpenAPI dengan NSwag.

Hasilkan kode dengan NSwagStudio

  • Instal NSwagStudio dengan mengikuti instruksi di repositori GitHub NSwagStudio. Pada halaman rilis NSwag, Anda dapat mengunduh versi xcopy yang dapat dimulai tanpa hak istimewa penginstalan dan admin.

  • Luncurkan NSwagStudio dan masukkan swagger.json URL file di kotak teks URL Spesifikasi Swagger. Contohnya,http://localhost:44354/swagger/v1/swagger.json.

  • Klik tombol Buat Salinan lokal untuk menghasilkan representasi JSON dari spesifikasi Swagger Anda.

    Membuat salinan lokal spesifikasi Swagger

  • Di area Output, klik kotak centang Klien CSharp. Bergantung pada proyek, Anda juga dapat memilih TypeScript Client atau CSharp Web API Controller. Jika Anda memilih CSharp Web API Controller, spesifikasi layanan membangun kembali layanan, berfungsi sebagai generasi terbalik.

  • Klik Hasilkan Output untuk menghasilkan implementasi klien C# lengkap dari proyek TodoApi.NSwag . Untuk melihat kode klien yang dihasilkan, klik tab Klien CSharp:

//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

namespace MyNamespace
{
    #pragma warning disable

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0))")]
    public partial class TodoClient
    {
        private string _baseUrl = "https://localhost:44354";
        private System.Net.Http.HttpClient _httpClient;
        private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            _httpClient = httpClient;
            _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() =>
            {
                var settings = new Newtonsoft.Json.JsonSerializerSettings();
                UpdateJsonSerializerSettings(settings);
                return settings;
            });
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set { _baseUrl = value; }
        }

        // code omitted for brevity

Tip

Kode klien C# dihasilkan berdasarkan pilihan di tab Pengaturan . Ubah pengaturan untuk melakukan tugas seperti penggantian nama namespace default dan pembuatan metode sinkron.

  • Salin kode C# yang dihasilkan ke dalam file di proyek klien yang akan menggunakan API.
  • Mulai gunakan API web:
 var todoClient = new TodoClient();

// Gets all to-dos from the API
 var allTodos = await todoClient.GetAllAsync();

 // Create a new TodoItem, and save it via the API.
var createdTodo = await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Mengkustomisasi dokumentasi API

Swagger menyediakan opsi untuk mendokumentasikan model objek untuk memudahkan konsumsi API web.

Info dan deskripsi API

Dalam metode , Startup.ConfigureServices tindakan konfigurasi yang diteruskan ke AddSwaggerDocument metode menambahkan informasi seperti penulis, lisensi, dan deskripsi:

services.AddSwaggerDocument(config =>
{
    config.PostProcess = document =>
    {
        document.Info.Version = "v1";
        document.Info.Title = "ToDo API";
        document.Info.Description = "A simple ASP.NET Core web API";
        document.Info.TermsOfService = "None";
        document.Info.Contact = new NSwag.OpenApiContact
        {
            Name = "Shayne Boyer",
            Email = string.Empty,
            Url = "https://twitter.com/spboyer"
        };
        document.Info.License = new NSwag.OpenApiLicense
        {
            Name = "Use under LICX",
            Url = "https://example.com/license"
        };
    };
});

UI Swagger menampilkan informasi versi:

Antarmuka pengguna Swagger dengan informasi versi

Komentar XML

Untuk mengaktifkan komentar XML, lakukan langkah-langkah berikut:

  • Klik kanan proyek di Penjelajah Solusi dan pilih Edit <project_name>.csproj.
  • Tambahkan baris yang disorot secara manual ke .csproj file:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Anotasi data

Karena NSwag menggunakan Reflection, dan jenis pengembalian yang direkomendasikan untuk tindakan API web adalah ActionResult<T>, NSwag hanya dapat menyimpulkan jenis pengembalian yang ditentukan oleh T. Anda tidak dapat secara otomatis menyimpulkan jenis pengembalian lain yang mungkin.

Pertimbangkan contoh berikut:

[HttpPost]
public ActionResult<TodoItem> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();

    return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

Tindakan sebelumnya mengembalikan ActionResult<T>. Di dalam tindakan, tindakan mengembalikan CreatedAtRoute. Karena pengontrol memiliki [ApiController] atribut , BadRequest respons juga dimungkinkan. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis. Gunakan anotasi data untuk memberi tahu klien kode status HTTP mana yang diketahui oleh tindakan ini. Tandai tindakan dengan atribut berikut:

[ProducesResponseType(StatusCodes.Status201Created)]     // Created
[ProducesResponseType(StatusCodes.Status400BadRequest)]  // BadRequest

Dalam ASP.NET Core 2.2 atau yang lebih baru, Anda dapat menggunakan konvensi alih-alih secara eksplisit menghiasi tindakan individual dengan [ProducesResponseType]. Untuk informasi selengkapnya, lihat Menggunakan konvensi API web.

Generator Swagger sekarang dapat secara akurat menggambarkan tindakan ini, dan klien yang dihasilkan tahu apa yang mereka terima saat memanggil titik akhir. Sebagai rekomendasi, tandai semua tindakan dengan atribut ini.

Untuk panduan tentang respons HTTP apa yang harus dikembalikan oleh tindakan API Anda, lihat RFC 9110: Semantik HTTP (Bagian 9.3. Definisi Metode).