Coder Social home page Coder Social logo

graphql's Introduction

GraphQL for Delphi

License

Simple implementation for GraphQL, a query language for APIs created by Facebook.

GraphQL is a query language for your API and a server-side runtime for executing queries using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.

See more complete documentation at https://graphql.org/.

Table of Contents

Features

GraphQL for Delphi supports only a basic part of the GraphQL specifications:

  • Fields
  • Arguments
  • Aliases

Other parts like variables, schema and validation are under development.

GraphQL tree navigation

The more basic feature of GraphQL for Delphi is the possibility to explore the GraphQL query.

With a code like this you can build the GraphQL tree:

  LBuilder := TGraphQLBuilder.Create(SourceMemo.Text);
  try
    // This will create the tree
    LGraphQL := LBuilder.Build;
  finally
    LBuilder.Free;
  end;

Then you will have a struture like this:

IGraphQL
├── Name
└── Fields
    ├── IGraphQLField (first entity)
    │   ├── Name
    │   ├── Alias
    │   ├── Arguments / Parameters
    │   │   ├─ IGraphQLArgument 
    │   │   └─ IGraphQLArgument 
    │   │
    │   └── IGraphQLValue (IGraphQLNull | IGraphQLObject)
    │       └─ Fields
    │          ├─ ...
    │          ├─ ...
    │
    └── IGraphQLField (second entity)
        ├── Name
        ├── Alias
        ├── ...

You can see the demo to have an idea of the capabilities of this library.

Query your API with GraphQL

First of all you need an API to query. At this moment GraphQL for Delphi supports classes or simple procedures and functions. In either case you have to tell the library how to call your API.

Basic API

If you have a simple API made of classic functions like this:

function RollDice(NumDices, NumSides: Integer): Integer;

function ReverseString(const Value: string): string;

function StarWarsHero(const Id: string): TStarWarsHero;

Then you need to register your API in this way:

  FQuery := TGraphQLQuery.Create;

  FQuery.RegisterFunction('rollDice',
    function (AParams: TGraphQLParams) :TValue
    begin
      Result := RollDice(AParams.Get('numDice').AsInteger, AParams.Get('numSides').AsInteger);
    end
  );

  FQuery.RegisterFunction('reverseString',
    function (AParams: TGraphQLParams) :TValue
    begin
      Result := ReverseString(AParams.Get('value').AsString);
    end
  );

  FQuery.RegisterFunction('hero',
    function (AParams: TGraphQLParams) :TValue
    begin
      Result := StarWarsHero(AParams.Get('id').AsString);
    end
  );

Eventually you can query your API:

json := FQuery.Run(MyQuery);

Run methods from a class using RTTI

If you have a class you need to tell the library:

  • how to create the instance;
  • if the class is a singleton (or if the library should create a new instance for every method call);
  • which methods GraphQL should query.

For example if you have a class like this:

  TTestApi = class(TObject)
  private
    FCounter: Integer;
  public
    [GraphQLEntity]
    function Sum(a, b: Integer): Integer;

    [GraphQLEntity('mainHero')]
    function MainHero: TStarWarsHero;

  end;

You need to add the GraphQLEntity to every method queryable by GraphQL and register the class:

  FQuery := TGraphQLQuery.Create;
  FQuery.RegisterResolver(TGraphQLRttiResolver.Create(TTestApi, True));

The RegisterResolver method can add a resolver (any class that implements IGraphQLResolver) to the GraphQL engine. A resolver is a simple object that explains to GraphQL how to get the data from the API. You can build your own resolvers or use the resolvers build-in with the library.

The TGraphQLRttiResolver is capable of running methods from a class using the RTTI.

Then you can query your API:

json := FQuery.Run(MyQuery);

A simple query:

How to use GraphQL aliases:

How to call simple functions:

A more complex example:

Use API from a ReST server

If you need to use GraphQL to queries a ReST API you can see the ProxyDemo. This simple project creates a basic HTTP server that responds to GraphQL query and uses a remote ReST API (https://jsonplaceholder.typicode.com/) as a data source.

The project uses a TGraphQLReSTResolver to map the GraphQL fields to the ReST API in this way:

  FQuery := TGraphQLQuery.Create;

  LResolver := TGraphQLReSTResolver.Create;

  // Basic entities
  LResolver.MapEntity('posts', 'https://jsonplaceholder.typicode.com/posts/{id}');
  LResolver.MapEntity('comments', 'https://jsonplaceholder.typicode.com/comments/{id}');
  LResolver.MapEntity('albums', 'https://jsonplaceholder.typicode.com/albums/{id}');
  LResolver.MapEntity('todos', 'https://jsonplaceholder.typicode.com/todos/{id}');
  LResolver.MapEntity('users', 'https://jsonplaceholder.typicode.com/users/{id}');

  // Entity details
  LResolver.MapEntity('users/posts', 'https://jsonplaceholder.typicode.com/users/{parentId}/posts');
  LResolver.MapEntity('users/comments', 'https://jsonplaceholder.typicode.com/users/{parentId}/comments');
  LResolver.MapEntity('users/todos', 'https://jsonplaceholder.typicode.com/users/{parentId}/todos');

  FQuery.RegisterResolver(LResolver);

When you define an entity you can specify the name of the id property (default "id"). The id propery will be used if your entity as a detail. For example you have a resource like:

https://jsonplaceholder.typicode.com/users/1
{
  "userId": 1,
  "name": "Luca"
}

and a detail resource like:

https://jsonplaceholder.typicode.com/users/1/todos
[{
  "id": 1,
  "userId": 1,
  "title": "Something to do"
},{
  "id": 2,
  "userId": 1,
  "title": "Another thing to do"
}]

You must define the entities in this way:

  LResolver.MapEntity('users', 'https://jsonplaceholder.typicode.com/users/{id}', 'userId');
  LResolver.MapEntity('users/todos', 'https://jsonplaceholder.typicode.com/users/{parentId}/todos');

Then, when you run the query with FQuery.Run(...), the resolver can call the right ReST API.

Todo

  • 🔥 Variables. GraphQL has a first-class way to factor dynamic values out of the query, and pass them as a separate dictionary. These values are called variables.
  • 🔥 Schemas, types and validation. Every GraphQL service defines a set of types which completely describe the set of possible data you can query on that service. Then, when queries come in, they are validated and executed against that schema.
  • 👍 Fragments. Fragments let you construct sets of fields, and then include them in queries where you need to.
  • Directives. A directive can be attached to a field or fragment inclusion, and can affect execution of the query in any way the server desires.
  • Mutations. Just like ReST any query can might end up causing some side-effects. However, it's useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.

graphql's People

Contributors

lminuti avatar paolo-rossi avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.