Skip to content

Getting Started: Minimal Web API

NeoDEEX 5.x 는 ASP.NET Core 의 Minimal API 방식을 통해 Fox Biz/Data Service Web API 를 제공할 수 있습니다. 이 문서는 Minimal api 방식으로 Fox Biz/Data Service Web API 를 사용하는 방법을 구체적으로 설명합니다.

Overview

ASP.NET Core Minimal API 는 최소한의 종속성으로 HTTP API를 만들도록 설계되었습니다. 최소한의 파일과 종속성, 기능만을 포함하기 때문에 Azure Functions 과 같은 server-less microservice 에 사용하기 적합합니다. 상세한 내용은 Minimal API 관련 문서를 참고 하십시요.

NeoDEEX 5.x 부터는 Minimal API 를 지원하기 위해 NeoDEEX.ServiceModel.WebApi nuget 패지키에서 다양한 확장 메서드(extension method)를 제공합니다. 이 문서를 통해 Visual Studio 를 사용하여 Minimal API 프로젝트를 생성하고 최소한의 코드 추가를 통해 Fox Biz/Data Service Web API 를 추가하는 방법에 대해 단계적으로 예제를 통해 설명합니다.

전체 예제 코드는 다음 링크를 참고 하십시요.

Creating a web api project

먼저, Visual Studio 를 사용하여 Minimal API 프로젝트를 생성합니다.

Note

이 문서에서 Visual Studio Code 를 사용하는 방법에 대해서는 설명하지 않습니다. 하지만, Visual Studio Code를 사용하여 동등한 기능을 동일하게 작성할 수 있습니다. 구체적인 방법은 MSDN의 Minimal API (VSCode) 예제를 참고하십시요.

  1. Visual Studio 에서 새 프로젝트를 생성을 수행합니다.

  2. 프로젝트 템플릿에서 ASP.NET Core Empty 템플릿을 선택합니다.

    Create New Project

  3. 프로젝트 이름을 입력합니다. 이 예제에서는 MinimalWebApi 라는 이름을 사용하였습니다.

  4. 프로젝트 추가 정보에서, 프레임워크로 .NET 8.0 을 선택하고 Do not use top-level statements 를 선택합니다.

    Additional Project Information

    Note

    Minimal API 예제에서는 Do not use top-level statements 설정을 선택하지 않았습니다. 이 차이는 Main 메서드의 유무 정도만 차이날 뿐 크게 다르지 않으므로 본 예제를 진행하는 것과 크게 다르지 않습니다.

  5. 프로젝트가 생성되면 빌드하고 테스트를 수행하여 어플리케이션이 정상적으로 작동하는지 확인합니다.

Adding Fox Biz Service

기본적인 Minimal Web API 를 생성하였으므로 이제 Fox Biz/Data Service Web API 를 추가하는 방법에 대해 단계적으로 알아 봅시다.

  1. 프로젝트의 NuGet 패키지 관리자를 구동하고 NeoDEEX.ServiceModel.WebApi 패키지를 검색하여 설치합니다.

    Add NeoDEEX.ServiceModel.WebApi Package

  2. Program.cs 파일의 Main 메서드 내에서 기존 MapGet 코드를 제거하고 Fox Biz Service 를 서비스하는 MapPost 메서드 호출을 추가합니다.

    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        var app = builder.Build();
    
        // FoxBizService 제공을 위한 MapPost 호출
        app.MapPost("/api/bizservice/{action}", async (HttpRequest httpRequest) =>
        {
            return await httpRequest.DispatchBizService();
        });
    
        app.Run();
    }
    

    자동으로 using 문이 추가되지 않았다면 NeoDEEX.ServiceModel.WebApi 네임스페이스에 대한 using 문을 추가해 줍니다.

    using NeoDEEX.ServiceModel.WebApi;
    

    Info

    Minimal API 환경에서는 서비스에 대한 About 페이지 기능을 제공하지 않습니다.

  3. BizLogic.cs 파일을 추가하고 비즈 로직 클래스 및 비즈 로직 메서드를 다음과 같이 작성합니다.

    using NeoDEEX.ServiceModel.Services.Biz;
    
    namespace MinimalWebApi;
    
    [FoxBizClass]
    public class BizLogic
    {
        [FoxBizMethod]
        public string Hello()
        {
            return "Hello Fox Biz Service World";
        }
    }
    

    Note

    FoxBizClassAttributeFoxBizMethodAttribute 는 Fox Biz Service 가 클라이언트에게 노출할 클래스와 메서드를 결정하는데 중요합니다. 이 두 특성이 명시되지 않으면 클라이언트는 비즈 서비스를 호출할 수 없습니다.

  4. 추가한 비즈 서비스를 테스트하기 위해 프로젝트에 HTTP 파일을 추가합니다.

    Add HTTP File

    1. 프로젝트 아이템 추가 메뉴를 선택합니다.
    2. 우측 상단 검색 창에 http 를 입력하고, 가운데 아이템 템플릿 목록에서 HTTP File 을 선택합니다.
    3. 하단 아이템 목록에 적절한 이름을 입력합니다. (이 예제는 test.http 을 사용)
    4. Add 버튼을 눌러 프로젝트에 추가합니다.
  5. Fox Biz Service 를 호출하도록 test.http 파일을 편집합니다. @host 변수에서 프로젝트마다 변경되는 포트 번호를 수정하십시요.

    # For more info on HTTP files go to https://aka.ms/vs/httpfile
    @host=localhost:7069
    
    POST https://{{host}}/api/bizservice/execute
    Content-Type: application/json
    
    {
        "classId": "MinimalWebApi.BizLogic",
        "methodId": "Hello"
    }
    
    ###
    
    • Main 메서드의 MapPost 호출에서 사용한 라우팅 템플릿(/api/bizservice/{action})과 일치하도록 url 을 설정하였음에 주목하십시요.
    • Content-Type 은 JSON 을 사용하며 호출하고자 하는 비즈 클래스를 classId 속성으로, 비즈 메서드 이름을 methodId 속성으로 명시하였습니다.
  6. test.http 파일에서 Send request 버튼을 클릭하여 Fox Biz Service 를 호출 합니다.

    Send request

  7. 호출 후, 우측 결과 패널에서 성공적으로 "Hello Fox Biz Service World" 가 반환되는지 확인하십시요.

    Biz Service Result

Adding Fox Data Service

이제 Fox Data Service Web API 를 추가해 봅시다. Fox Data Service 는 데이터베이스를 액세스하기 때문에 데이터베이스 액세스를 위한 패키지를 추가해야 합니다.

  1. 이 예제에서는 SQL Server 의 Northwind 데이터베이스를 액세스하기 때문에 NuGet 패키지 관리자를 구동하고 NeoDEEX.Data.SqlClient 패키지를 설치합니다. 사용자의 데이터베이스에 따라서 다음 패키지를 선택하여 설치하도록 합니다.

    • Oracle : NeoDEEX.Data.OracleClient
    • PostgreSQL : NeoDEEX.Data.NpgsqlClient
    • MySQL : NeoDEEX.Data.MySqlClient
    • ODBC : NeoDEEX.Data.Odbc

    Add Database Package

  2. Main 메서드에 MapPost 메서드 호출을 추가하여 Fox Data Service 에 대한 Web API 를 활성화 합니다.

    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        var app = builder.Build();
    
        app.ConfigureBizService();
    
        // FoxBizService 를 위한 MapPost 호출
        app.MapPost("/api/bizservice/{action}", async (HttpRequest httpRequest) =>
        {
            return await httpRequest.DispatchBizService();
        });
    
        // FoxDataService 를 위한 MapPost 호출
        app.MapPost("/api/dataservice/{action}", async (string action, HttpRequest httpRequest) =>
        {
            return await httpRequest.DispatchDataService(action);
        });
    
        app.Run();
    }
    
  3. 데이터베이스 연결 문자열 등을 위해 NeoDEEX 구성 설정 파일을 추가 합니다. 프로젝트 아이템 추가 메뉴를 선택하고 JSON 파일 템플릿에서 파일 이름을 neodeex.config.json 로 지정합니다.

    Warning

    NeoDEEX 구성 파일 이름은 명시적으로 바꾸지 않는 한 neodeex.config.json 이므로 파일 이름 지정에 주의해야 합니다.

    솔루션 탐색기에서 추가된 neodeex.config.json 파일을 선택하고 설정(properties)에서 Copy to Output Directory 속성의 값이 Copy if newer 임을 확인하십시요.

    Set Copy if Newer

  4. neodeex.config.json 파일의 내용은 다음과 같이 지정합니다.

    {
      "database": {
        "connectionStrings": {
          "default": {
            "type": "NeoDEEX.Data.SqlClient.FoxSqlDbAccess",
            "connectionString": "SERVER=(LocalDB)\\MSSQLLocalDB;DATABASE=Northwind;Trusted_Connection=True"
          }
        }
      }
    }
    

    SQL Server 대신 다른 데이터베이스를 사용한다면 type 속성의 값을 다음과 같이 지정하고, 각 데이터베이스에 맞는 연결 문자열을 사용하십시요.

    • Oracle: NeoDEEX.Data.OracleClient.FoxOracleDbAccess
    • PostgreSQL: NeoDEEX.Data.NpgsqlClient.FoxNpgsqlDbAccss
    • MySQL: NeoDEEX.Data.MySqlClient.FoxMysqlDbAccess
    • ODBC: NeoDEEX.Data.Odbc.FoxOdbcDbAccess
  5. 이제 Fox Data Service 를 통해 수행할 쿼리들을 담는 쿼리 맵 파일을 추가해야 합니다. 먼저 프로젝트에 foxml 폴더를 추가합니다.

    Info

    구성 설정에 queryMappers 설정을 추가하지 않는 경우, FoxDbAccess 는 자동으로 ./foxml 폴더에서 FoxQuery 파일들을 읽도록 쿼리 매퍼를 구성합니다.

  6. 추가된 foxml 폴더에 FoxQuery 파일을 추가합니다. 프로젝트 아이템 추가 메뉴를 선택하고 XML 파일 템플릿을 선택하고 파일 이름으로 Northwind.foxml 을 지정합니다.

    Warning

    FoxQuery 파일의 확장자는 반드시 .foxml 이어야만 합니다.

    Add Foxml File

    구성 파일과 마찬가지로 추가된 Northwind.foxml 파일의 Copy to Output Directory 속성의 값을 Copy if newer 으로 지정하십시요. 이 설정이 없다면 .foxml 파일이 복사되지 않기 때문에 Fox Data Service 호출에서 오류가 발생하게 됩니다.

  7. Northwind.foxml 파일의 내용에 다음과 같이 SQL 문장을 입력하십시요.

    <?xml version="1.0" encoding="utf-8" ?>
    <queryMap xmlns="http://schema.neodeex.net/fx/foxml/2023/04/">
      <statements>
        <statement id="GetProducts">
          <text>
            SELECT * FROM Products WHERE ProductID = #productid#
          </text>
          <parameters>
            <parameter name="productid"/>
          </parameters>
        </statement>
      </statements>
    </queryMap>
    
  8. Fox Biz Service 테스트와 동일하게 test.http 파일을 편집하여 Fox Data Service 를 호출하도록 POST 를 다음과 같이 추가합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    POST https://{{host}}/api/dataservice/executeDataSet
    Content-Type: application/json
    
    {
      "queryId": "Northwind:GetProducts",
      "parameters": {
        "productid": 1
      }
    }
    

    호출하고자 하는 FoxQuery의 아이디를 queryId 속성에 명시하였음에 주목하십시요. FoxQuery 아이디는 FoxQuery 파일 이름(Northwind)과 파일 내에 존재하는 쿼리의 아이디(GetProducts)를 콜론 문자로 조합한 것입니다.

  9. 새로이 추가된 POST 에 대해 Send Request 버튼을 클릭하여 테스트 서비스를 호출하고 호출 결과로 데이터가 반환되는 것을 확인하십시요.

    DataService Result

Customizing Web API

Minimal Web API 는 유연하게 Fox Biz/Data Service 에 대해 다양한 커스터마이징이 가능합니다. 이 예제에서는 Fox Biz/Data Service Web API 구성 설정을 변경하거나 서비스 호출 url 을 커스터마이징 하는 예제를 살펴볼 것입니다.

Service configuration

Fox Biz/Data Service Web API 에 대한 다양한 설정은 일반적으로 neodeex.config.json 구성 설정 파일을 통해 수행됩니다. 하지만 Minimal Web API 를 사용하면 간단한 설정은 구성 설정을 변경하지 않고도 설정이 가능합니다. DispachBizService 혹은 DispatchDataService 메서드를 호출할 때 옵션 설정을 전달할 수 있으며 이 옵션 설정을 통해 몇가지 핵심 설정을 변경할 수 있습니다.

기본적으로 Fox Biz/Data Service 는 서비스 호출 결과를 반환할 때 데이터 타입도 반환합니다. 앞서 Fox Biz Service 호출을 테스트한 결과를 상세히 살펴보면 다음과 같습니다.

{
  "success": true,
  "elapsedMilliseconds": 101,
  "result": {
    "$type": "string",
    "value": "Hello Fox Biz Service World"
  },
  "serverInfo": {
    "machineName": "NEOWORK",
    "ip": "192.168.0.33;172.22.144.1"
  }
}

Fox Biz Service의 호출 결과는 result 속성을 통해 반환되는데, 이 결과가 string 타입임을 나타내는 $type 속성 역시 포함하고 있습니다. $type 을 통해 제공되는 데이터 타입 정보는 C# 과 같이 타입에 강력하게 연결된 환경에서는 유용하지만 Javascript 와 같이 데이터 타입에 구애 받지 않는 환경에서는 불편한 요소가 됩니다.

데이터 타입 정보를 반환하지 않도록 FoxBizServiceDispatchOptions 객체를 생성하고 UseTypeInfo 속성 값을 false 로 설정합니다. 그리고 이 객체를 DispatchBizService 메서드 호출에 매개변수로 사용하면 됩니다.

1
2
3
4
5
6
7
8
9
// FoxBizService 를 위한 MapPost 호출
FoxBizServiceDispatchOptions options = new()
{
    UseTypeInfo = false
};
app.MapPost("/api/bizservice/{action}", async (HttpRequest httpRequest) =>
{
    return await httpRequest.DispatchBizService(options);
});

이제 비즈 서비스 호출은 다음과 같이 테이터 타입 정보를 포함하지 않는 JSON 을 반환합니다.

1
2
3
4
5
6
7
8
9
{
  "success": true,
  "elapsedMilliseconds": 3,
  "result": "Hello Fox Biz Service World",
  "serverInfo": {
    "machineName": "NEOWORK",
    "ip": "192.168.0.33;172.22.144.1"
  }
}

UseTypeInfo 속성과 유사하게, 보안 상 해커에게 유용한 정보를 제공할 수도 있는 서버 측 정보를 반환하지 않도록 ReturnServerInfo 속성을 false 로 지정할 수도 있습니다.

1
2
3
4
5
FoxBizServiceDispatchOptions options = new()
{
    UseTypeInfo = false,
    ReturnServerInfo = false,
};

이 경우, 반환되는 JSON 은 다음과 같습니다.

1
2
3
4
5
{
  "success": true,
  "elapsedMilliseconds": 3,
  "result": "Hello Fox Biz Service World"
}

Url Customizing

Minimal Web API 는 컨트롤러 기반의 Web API 에 비해 서비스에 대한 url 커스터마이징이 좀 더 자유롭습니다. MapGet 메서드와 MapPost 메서드를 활용하여 Fox Biz/Data Service 를 호출하는 방식을 변경할 수 있습니다.

다음 예제 코드는 /api/dataservice 대신 /api/northwind/products 경로를 사용하며 FoxDataService 클래스의 ExecuteDataSet 메서드를 호출하도록 하는 새로운 MapPost 호출의 예를 보여줍니다.

// FoxDataService 를 위한 MapPost 호출
FoxDataServiceDispatchOptions dataOptions = new()
{
    UseTypeInfo = false,
    ReturnServerInfo = false,
};
app.MapPost("/api/dataservice/{action}", async (string action, HttpRequest httpRequest) =>
{
    return await httpRequest.DispatchDataService(action);
});
// Url 커스터마이징
app.MapPost("/api/northwind/products", async (HttpRequest httpRequest) =>
{
    return await httpRequest.DispatchDataService("ExecuteDataSet", dataOptions);
});

앞서 테스트에 사용했던 .http 파일에서 url 을 다음과 같이 변경하면 동일한 호출 결과를 얻을 수 있습니다.

POST https://{{host}}/api/northwind/products

MapGet 호출을 사용하여 RESTful 스타일의 Web API 를 구성하는 것도 가능합니다. 다음 코드는 /api/products/{id} 템플릿을 사용하여 조회하고자 하는 제품 Id를 url에서 추출합니다. POST 를 사용하는 예제에서는 클라이언트가 FoxDataRequest 객체를 JSON 으로 전송하였지만, 이 예제는 코드 내에서 직접 FoxDataRequest 객체를 생성하여 FoxQuery 아이디와 매개변수를 설정합니다. 이와 같이 FoxDataRequest 객체를 직접 생성하거나 수동으로 역직렬화하는 경우, DispatchDataRequest 메서드를 호출하여 FoxDataService 클래스의 메서드를 직접 호출해야 합니다.

또한 이 예제에서는 FoxDataResponse 객체를 반환하는 것이 아닌 DataTable 객체를 반환합니다. 이를 위해 JsonSerializerOptions 객체를 생성하고 DataTable 을 JSON 으로 직렬화하기 위한 JsonConverter 를 추가하였습니다.

// REST 스타일 Data Service
JsonSerializerOptions jsonOptions = new();
jsonOptions.Converters.Add(new FoxDataTableConverter() { UseTypeInfo = false });
app.MapGet("/api/products/{id}", (string id, HttpRequest httpRequest) =>
{
    FoxDataRequest request = new("Northwind:GetProducts");
    request["productid"] = id;

    FoxDataResponse response = httpRequest.DispatchDataRequest(service => service.ExecuteDataSet(request), dataOptions);
    return Results.Json(response.DataSet.Tables[0], jsonOptions);
});

Warning

JsonSerializerOptions 객체를 MapGet 호출의 내부 로컬 변수로 사용하지 않도록 주의하십시요. JsonSerializerOptions 객체는 System.Text.Json 네임스페이스 직렬화와 관련된 다양한 캐시를 포함하기 때문에 매 호출마다 이 객체를 생성하면 성능 저하와 메모리 사용량이 크게 증가하게 됩니다.

이제 .http 파일에서 다음과 같은 호출을 사용하여 위 RESTful API 를 테스트할 수 있습니다.

GET https://{{host}}/api/products/2

위 호출은 다음과 같은 결과를 반환할 것입니다.

[
  {
    "ProductID": 2,
    "ProductName": "Chang",
    "SupplierID": 1,
    "CategoryID": 1,
    "QuantityPerUnit": "24 - 12 oz bottles",
    "UnitPrice": 19.0000,
    "UnitsInStock": 17,
    "UnitsOnOrder": 40,
    "ReorderLevel": 25,
    "Discontinued": false
  }
]

Summary

ASP.NET Core Minimal API 는 최소의 의존성과 코드로 Web API 를 작성할 수 있는 아키텍처를 제공합니다. Fox Biz/Data Service Web API 는 Minimal API 환경에서 Fox Biz/Data Service 에 대한 Web API 를 제공할 수 있는 다양한 확장을 제공합니다. 이를 통해 유연한 Web API 를 클라이언트에게 제공할 수 있습니다.