OData zamiast klasycznego podejścia do REST: jakie jest Wasze zdanie

0

Witam,
Temat jest bardziej ogólny, bo dotyczy integracji, ale ponieważ standard był mocno promowany przez MS w .NET (ostatnio podchwycony również przez SAP) dlatego został założony w dziale .NET.

Usługa OData jest bardziej skomplikowana po stronie serwera niż typowy kontroler REST np. *MVC, JAX-RS ponieważ może obsługiwać pewne elementy SQLa. Wydaje mi się, że szybciej i prościej wystawić specjalistyczną usługę REST. Generyczne usługi, które potrafią wszystko wydają mi się znacznym przyrostem formy nad treścią: trochę jak EJB 2.1. Co najwyżej mogą mieć sens, jeśli chcemy zdalnie udostępnić bazę danych za pomocą generycznego standardu dostępu do danych w środowisku mikrousług, gdzie wysoki poziom transakcyjności nie jest wymagany.

Wydaje mi się to ukłon w stronę frontend developera (bo może robić z kolekcjami co chce), kosztem utrudnienia życia backend developera. Chyba, że usługa zostanie w prosty sposób "wygenerowana" / wyklikana z istniejącego opisu encji.

Mam z tym związanych kilka pytań:

  1. Czy i kiedy używacie standardu OData?
  2. Czy jesteście skłonni zrezygnować z klasycznych prostych usług REST na rzecz OData (potenjalna zaleta, precyzyjny opis kontraktu usługi)?
  3. Czy używacie usług OData poza światem Microsoft? Np. Apache Olingo albo SAP Netweaver Gateway.
  4. Czy Waszym zdaniem warto znać OData?

Pozdrawiam,

0

Ja stale używam oData w SAP Fiorii. Zastanawiam sie właśnie, czy nie zastąpić api dla mobilnych urządzeń na oDate, bo mógłbym mieć wspólny rdzeń dla mobilek i stronki pod fiorii w jednym.

1

Jakiś czas temu zastanawiałem się nad OData. Potrzebowałem przekazać z aplikacji do WebAPI jakiś prosty filtr. OData wydało mi się trochę przerostem formy nad treścią. Więc stworzyłem własny przerost formy nad treścią :D

Rozwiązanie jest proste. Stworzyłem na początek klasę QueryFilter wraz z pochodnymi:

    public enum OrderDirection
    {
        NoOrder,
        Ascending,
        Descending
    }

    public class OrderInfo
    {
        /// <summary>
        /// Direction of order. NoOrder means that no ordering is done.
        /// </summary>
        public OrderDirection Direction { get; set; }

        /// <summary>
        /// Ordering field
        /// </summary>
        public string FieldName { get; set; }
    }


    /// <summary>
    /// Use this class to filter through WebAPI.
    /// </summary>
    /// <typeparam name="T">Model that is going to be filtered</typeparam>
    public class QueryFilter<T> where T: class
    {
        /// <summary>
        /// "Where" condition. This is lambda expression.
        /// </summary>
        public Expression<Func<T, bool>> Where { get; set; }

        /// <summary>
        /// Order by
        /// </summary>
        public OrderInfo OrderBy { get; set; }

        /// <summary>
        /// How many records should be skipped. Mainly for pagination
        /// </summary>
        public int Skip { get; set; }

        /// <summary>
        /// How many records should be retrieved. Mainly for pagination
        /// </summary>
        public int Max { get; set; }

        public QueryFilter()
        {
            OrderBy = new OrderInfo();
            OrderBy.Direction = OrderDirection.NoOrder;
        }

        public static QueryFilter<T> FromDto(QueryFilterDto dto, Expression<Func<T, bool>> where)
        {
            QueryFilter<T> result = new QueryFilter<T>();
            result.Max = dto.Max;
            result.OrderBy = dto.OrderBy;
            result.Skip = dto.Skip;
            result.Where = where;

            return result;
        }

        public void CreateWhere(Expression<Func<T, bool>> where)
        {
            Where = where;
        }

        public void CreateOrder(OrderDirection direction, string fieldName)
        {
            OrderBy.Direction = direction;
            OrderBy.FieldName = fieldName;
        }
    }

    /// <summary>
    /// This is helper class that is send between client and WebApi. Use generic QueryFilter instead
    /// </summary>
    public class QueryFilterDto
    {
        public string ModelName { get; set; }
        public string Where { get; set; }
        public OrderInfo OrderBy { get; set; }
        public int Skip { get; set; }
        public int Max { get; set; }
    }

Następnie wysyłam to JSonem do WebApi.
Po stronie WebApi najważniejsze jest to:

Expression<Func<Order, bool>> where = await Utils.ExpressionFromStr<Order>(filterDto.Where);

ExpressionFromStr wygląda tak:

using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;

public async static Task<Expression<Func<T, bool>>> ExpressionFromStr<T>(string expressionStr)
{
    var options = ScriptOptions.Default.AddReferences(typeof(T).Assembly);
    return await CSharpScript.EvaluateAsync<Expression<Func<T, bool>>>(expressionStr, options);
}

Oczywiście wymaga to Roslyn. Na szczęście te usingi można prosto pobrać z NuGeta.
Mając takie lambda expression można już przekazać je do jakiegoś ORMa albo LinqToSql.

1 użytkowników online, w tym zalogowanych: 0, gości: 1