A middleware that translates GraphQL to OData
Best to use a tool like Postman or Insomnia
Once your run the project (F5 or dotnet run), go to https://localhost:<port>/odata/$graphql
using one of the above tools.
Set Content-Type
to application/json
and then using raw json, send a request as shown below
{
"query":
"
query SampleQuery
{
Customers { id title }
...
}
...
"
}
That's it!
Important Note: Unfortunately it's not yet possible to use Postman's GraphQL client since it expects either a graphql schema or introspection support.
Introspection is not currently supported which means autocompletion and GraphiQL are not supported.
Queries are used to support the equivalent standard get requests such as /Books/
as well as OData functions.
query
{
Customers { id name email } # entity set
GetSomeBook(title: "The Capitalist Economy") { id title }
}
Filtering is supported via the where
clause along with various comparison operators added as suffix extensions to the field names.
Supported filtering suffixes include:
- logical operators:
lt
,lte
,gt
,gte
- string operators:
startswith
,endswith
,contains
You can use or
and and
in the filters to support more complex filtering.
Ordering is also supported via the order_by
operator.
You can you also use first
and last
keywords to get limit the number of records returned.
query BooksAndCustomers
{
books(where: { or : { id_lt : 2, title_contains: "Economy" }}) { id title author }
customers(first: 2, order_by: [name_asc, id_desc]) { id name email }
GetSomeBook(title: "The Capitalist Economy") { id title author }
}
Fragments area also supported
query BooksAndCustomers
{
Books(where: { or : { id_lt : 2, title_contains: "Economy" }}) { ...fullBook }
Customers {
id
name
PrimaryEmail: email # property name aliasing
}
GetSomeBook(title: "The Capitalist Economy") { ...simpleBook}
}
fragment simpleBook on Books
{
id
title
}
fragment fullBook on Books
{
id
title
author
price
}
Mutations support both CRUD modification operations (i.e. create, update, delete) as well as OData actions.
CRUD modification operations are supported via the _add
, _update
and _delete
suffixes using the following format - EntitySet_<prefix>
Example: Books_add
, Books_update
, Books_delete
.
The input values for mutations are passed in via an input
object for both CRUD modifiers and OData actions.
update
and delete
operations expect an id
field which will be passed as the key segment for the specific entity to be modified.
Example:
mutation BookMutations
{
Books_add(input: { title: "river and the source", author: "mister man" }) { id }
Books_update(id: 12, input: { title: "The man from mars" }) { id }
Books_delete(id: 11) { id }
}
will be translated into the following:
POST /Books
{ title: "river and the source", author: "mister man" }
PATCH /Books(12)
{ title: "The man from mars" }
DELETE /Books(12)
IMPORTANT NOTE: GraphQL expects all operations to return an object with at least one property. OData however, only optionally returns data from CRUD modification operations. The HTTP response status code 204
for instance returns NO CONTENT
which means there's no response payload. You can therefore add anything in the expected GraphQL response properties.
mutation
{
AddBook(input: { id: 25, title: "small things", author: "no name" }) { ...fullBook }
}
The following aggregations are supported: sum
, min
, max
, average
, countdistinct
, $count
via the following syntax
<entity set>_aggregate { ... }
.
groupby
is also supported by using the group_by
as shown in the example below.
$count
is represented by _count
since graphql will not allow field names starting with $
.
For the individual properties that you want to aggregate, you should use the following syntax <field name>_<aggregation>
.
Example:
Books_aggregate(group_by: [Id, Author], order_by: [Author_desc])
{
price_sum
AvgBookPrice: price_average # example using prop name aliasing
price_max
price_min
id_countdistinct
_count # this is how we represent OData's $count
}
- handling entity set queries
- handling functions and actions
- handling variables
- translate to $expand, query fields that have selection sets
- translate updates to patch http method (not post)
- translating fragments
- support custom filtering options per field e.g. for playground and Hasura
- support order by
- response pipeline to reformat OData response to graphql response
- filter on nav props
- translate deletes to delete http method (not post)
- using bulk operations for insert/update/delete
- aggregations (sum, min, max, average, countdistinct, $count)
- support property aliases
- support order_by in aggregation
- aggregate across nav props and complex types
- generate graphql schema from OData schema to allow graphql introspection by tools like graphiql
- casting derived types
- handling nav props - single/multi/complex type using direct nav syntax e.g. /Customers(1)/Trips(1)/
- Migrate from newtonsoft.json to system.text.json
- Support supplying external sources (e.g. Tripin)