3

Slim 4 - GraphQL

 2 years ago
source link: https://odan.github.io/2021/08/12/slim-graphql.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Daniel Opitz

Daniel Opitz - Blog

Developer, Trainer, Open Source Contributor

Blog About me Donate

Slim 4 - GraphQL

Daniel Opitz

Daniel Opitz

12 Aug 2021

Table of contents

Introduction

GraphQL is a modern way to build HTTP APIs consumed by the web and mobile clients. It is intended to be an alternative to REST and SOAP APIs.

GraphQL itself is a specification designed by Facebook engineers. Various implementations of this specification were written in different languages and environments.

The Graph API is the primary way to get data into and out of a platform. It’s an HTTP-based API that apps can use to programmatically query data, post new entries, upload things, and perform a wide variety of other tasks.

Requirements

This documentation assumes your familiarity with GraphQL concepts. If it is not the case - first learn about GraphQL on the official website.

Other requirements:

Installation

For this Slim framework tutorial I will use the most popular graphql-php component. graphql-php is a feature-complete implementation of GraphQL specification in PHP. This library is a thin layer around your existing data layer and business logic. It does not dictate how these layers are implemented or which storage engines are used. Instead, it provides tools for creating rich APIs for your existing application.

Use Composer to install the graphql-php component:

composer require webonyx/graphql-php

Install Tools (optional)

For development and testing purposes you may install a GraphQL tool like Postman.

I know what you say now. Many people think of Postman as an advanced REST client. Beyond REST, Postman is a tool that handles any calls sent over HTTP. This means that you can use Postman to interact with protocol-agnostic APIs - such as SOAP and GraphQL, which can both utilize HTTP, just like REST.

Learn more: Postman - Querying with GraphQL

Hello World

GraphQL is composed of nodes, edges, and fields. Typically you use nodes to get data about a specific object, use edges to get collections of objects on a single object, and use fields to get data about a single object or each object in a collection.

Let’s create a new GraphQL “endpoint” that will be capable to process the following simple query:

query {
  echo(message: "Hello World")
}

In Slim you could create and endpoint that handles the “Hello World” query as follows:

Add this (empty) route that acts as our GraphQL endpoint.

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

// ...
$app->post('/hello', function (ServerRequestInterface $request, ResponseInterface $response) {
 // put your code here...
});

To handle the “echo” query we create an GraphQL\Type\Definition\ObjectType instance and pass the configuration with the echo field, the return type, the arguments and the resolver callback function.

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;

$queryType = new ObjectType(
    [
        'name' => 'Query',
        'fields' => [
            'echo' => [
                'type' => Type::string(),
                'args' => [
                    'message' => Type::nonNull(Type::string()),
                ],
                'resolve' => function ($rootValue, $args) {
                    return $rootValue['prefix'] . $args['message'];
                }
            ],
        ],
    ]
);

$schema = new Schema(['query' => $queryType]);

To make the following code work, you have to ensure that the Slim BodyParsingMiddleware has been added to the middleware stack:

// config/middleware.php
$app->addBodyParsingMiddleware();

Next, we have to fetch the raw body content from the request object and decode it from json to an array.

$input = $request->getParsedBody();
$query = $input['query'];
$variables = $input['variables'] ?? null;

If you do not add the BodyParsingMiddleware to the middleware stack, you need to decode the request manually as described below:

$input = (array)json_decode((string)$request->getBody(), true);

To execute the actual query we pass all we have to the static GraphQL::executeQuery method:

use GraphQL\GraphQL;
// ...

try {
    $rootValue = ['prefix' => 'You said: '];
    $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variables);
    $output = $result->toArray();
} catch (Exception $exception) {
    $output = [
        'errors' => [
            [
                'message' => $exception->getMessage()
            ]
        ]
    ];
}

The final step is to put this output into our PSR-7 response object:

$response = $response->withHeader('Content-Type', 'application/json');
$response->getBody()->write(json_encode($output));

return $response;

Ok fine, let’s open Postman and see if it works.

Change the HTTP method to POST and enter the url of your endpoint.

Change the schema to GrapgQL and paste this query into the “Query” textfield:

query {
  echo(message: "Hello World")
}

Click the “Send” button to submit the request.

The result should look like this:

image

Security

Please note that GraphQL is susceptible to the following attack vectors (among others):

  • The single endpoint provides access to all information from the website, so we could have private data unintentionally exposed.
  • The queries can be very complex and may overwhelm the web and database servers.
  • The same mutation can be executed multiple times in a single query, and multiple queries can be executed together in a single request, allowing attackers to attempt gaining access to the back-end by providing many combinations of user/passwords.

These attacks can happen with GraphQL, and not with REST, because GraphQL is more powerful than REST. While in REST the query is defined in advance and stored in the server, in GraphQL it is provided on runtime by the client (unless using persisted queries).

Conclusion

Of course, this article shows only a very short sample of what is possible. Next, for instance, you could continue to generate your dynamic database queries, etc. However, I only wanted to simplify the first step for you and give you the opportunity to develop it further.

Opinion: I don’t think you need GraphQL as long as your REST API meets your requirements. For security and data privacy reasons, the most business logic and (database) queries should be defined, created and executed by the server anyway (and not by the client).

Just to be sure: I’m not advocating to not use GraphQL, but please use GraphQL responsibly. GraphQL is powerful, which means it is dangerous. If you use GraphQL after all, you must be quite absolutely sure that you know what you are doing.

Read more

© 2021 Daniel Opitz | Twitter


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK