SlideShare a Scribd company logo
Creating a modern web
application using Symfony API
Platform, ReactJS and Redux
by Jesus Manuel Olivas / weKnow
@jmolivas
● WHO AM I?
Jesus Manuel Olivas
jmolivas@weknowinc.com
jmolivas
jmolivas
drupal.org/u/jmolivas
jmolivas.weknowinc.com
WeGive
2,572,697
WeAre
WeKnow
Symfony
API Platform / GraphQL
 ReactJS / Redux / Saga
Ant Design
Symfony Flex
Symfony Flex … a Composer plugin for Symfony
> Symfony Flex is a Composer plugin that modifies the behavior of
the require, update, and remove composer commands.
> Symfony Flex automates the most common tasks of Symfony
applications, like installing and removing bundles and other
dependencies using recipes defined in a manifest.json file.
Directory structure
API Platform 
Framework
The API Platform Framework
REST and GraphQL
framework to build
modern API-driven
projects
https://api-platform.com/
Built on the Shoulders of Giants
> Extend the framework with thousands of existing Symfony
bundles and React components.
> The API component includes the Symfony 4 flex, the Doctrine ORM.
Client-side components and Admin based on React and a Docker
configuration ready to startup your project using one single command.
> Reuse all your Symfony, React and Docker skills and benefit of their high
quality docs; you are in known territory.
The API Platform Components
API Schema Admin CRUD
Try API-Platform
# Clone code repository

git clone https://github.com/api-platform/api-platform.git
Recommendations and adjustments
> Update route prefix at api/config/routes/api_platform.yaml
file.
api_platform:

…

prefix: /api
> Update admin/.env and client/.env files (change protocol and port).
REACT_APP_API_ENTRYPOINT=http://localhost:8080/api
Start containers … and grab water, coffee, or a beer.
# Start containers
ahoy up
# Open browser
open http://localhost/
Add more formats
Update api/config/packages/api_platform.yaml adding:
formats:
jsonld: [‘application/ld+json'] # first one is the default format
json: ['application/json']
jsonhal: ['application/hal+json']
xml: ['application/xml', 'text/xml']
yaml: ['application/x-yaml']
csv: ['text/csv']
html: ['text/html']
Add Dependencies
> Add new entities to api/src/Entity/ directory:

ahoy console make:entity



> Remove default entity

api/src/Entity/Greeting.php
Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA
Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA
Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA
Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA
api/src/Entity/Post.php 1/3
<?php

namespace AppEntity;



use ApiPlatformCoreAnnotationApiResource;

use DoctrineORMMapping as ORM;

use SymfonyComponentValidatorConstraints as Assert;
/**

* @ApiResource

* @ORMTable(name="post")

* @ORMEntity

*/
class Post
{
…
}
api/src/Entity/Post.php 2/3
/**

* @ORMId

* @ORMGeneratedValue(strategy="AUTO")

* @ORMColumn(type="integer")

*/

private $id;
/**

* @ORMColumn

* @AssertNotBlank

*/

public $title = '';

/**

* @ORMColumn
* @AssertNotBlank
*/
public $body = '';
api/src/Entity/Post.php 3/3
/**
* @ORMManyToOne(targetEntity="PostType")
* @ORMJoinColumn(name="post_type_id", referencedColumnName="id", nullable=false)
*/
public $type;
public function getId(): int
{
return $this->id;
}
Tracking Database changes
# Add dependency
ahoy composer require migrations
# Execute command(s)
ahoy console make:migration
ahoy console doctrine:migrations:migrate
Add FOSUserBundle
# Add dependency
composer require friendsofsymfony/user-bundle
composer require symfony/swiftmailer-bundle
https://symfony.com/doc/current/bundles/FOSUserBundle/index.html
https://jolicode.com/blog/do-not-use-fosuserbundle
Initialize the project
> Drop and Create Database
> Execute Migrations
> Populate Entities with Data
bin/console init
Use:

hautelook/alice-bundle 

doctrine/data-fixtures
Loading Posts using the Browser
http://localhost:8080/api/posts
http://localhost:8080/api/posts.json
http://localhost:8080/api/posts.jsonld
http://localhost:8080/api/posts/1
http://localhost:8080/api/posts/1.json
Loading Posts using the CLI
curl -X GET "http://localhost:8080/api/posts" 
-H "accept: application/json"
curl -X GET "http://localhost:8080/api/posts/1" 
-H "accept: application/ld+json"
ADD Posts from CLI
curl -X POST "http://localhost:8080/api/posts" 
-H "accept: application/ld+json" 
-H "Content-Type: application/ld+json" 
-d '{ "title": "Post create from CLI", "body": "body-
less", "type": "/api/post_types/1"}'
UPDATE and REMOVE Posts from CLI
curl -X PUT "http://localhost:8080/api/posts/9" 
-H "accept: application/ld+json" 
-H "Content-Type: application/ld+json" 
-d '{ "title": "Updated from CLI"}'
curl -X DELETE "http://localhost:8080/api/posts/10" 
-H "accept: application/json"
Serialization
> API Platform allows to specify the which attributes of the resource are
exposed during the normalization (read) and denormalization (write)
process. It relies on the serialization (and deserialization) groups feature of
the Symfony Serializer component.
> In addition to groups, you can use any option supported by the Symfony
Serializer such as enable_max_depth to limit the serialization depth.
Serialization Relations (Post => PostType) 1/2
# api/src/Entity/Post.php & PostType.php
* @ApiResource(attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"write"}}
* })
Serialization Relations (Post => PostType) 2/2
# Add use keyword to class
use SymfonyComponentSerializerAnnotationGroups;
# Add use keyword to properties
* @Groups({"read"})
* @Groups({"read", "write"})
GraphQL
GraphQL
GraphQL offers significantly more flexibility for integrators.
Allows you to define in detail the only the data you want.
GraphQL lets you replace multiple REST requests with a single
call to fetch the data you specify.
Add GraphQL
To enable GraphQL and GraphiQL interface in your API, simply require
the graphql-php package using Composer:
composer require webonyx/graphql-php
open http://localhost:8080/api/graphql
Disable GraphiQL
Update api/config/packages/api_platform.yaml adding:
api_platform:
# ...
graphql:
graphiql:
enabled: false
# ...
Load resource using GraphQL
{
post (id:"/api/posts/1") {
id,
title,
body
}
}
Load resource using GraphQL form the CLI
curl -X POST 
-H "Content-Type: application/json" 
-d '{ "query": "{ post(id:"/api/posts/1") { id,
title, body }}" }' 
http://localhost:8080/api/graphql
Load resource relations using GraphQL
{
post (id:"/api/posts/1") {
title,
body,
type {
id,
name,
}
}
}
Load resource relations using GraphQL form the CLI
curl -X POST 
-H "Content-Type: application/json" 
-d '{ "query": "{ post(id:"/api/posts/1") { id, title,
body, type { id, name } }}" }' 
http://localhost:8080/api/graphql
JWT
JWT Dependencies
# JWT
composer require lexik/jwt-authentication-bundle
JWT Refresh

gesdinet/jwt-refresh-token-bundle
JWT Events (create)
# config/services.yaml

AppEventListenerJWTCreatedListener:

tags:

- {

name: kernel.event_listener, 

event: lexik_jwt_authentication.on_jwt_created,

method: onJWTCreated

}


# src/EventListener/JWTCreatedListener.php

public function onJWTCreated(JWTCreatedEvent $event)

{

$data = $event->getData();

$user = $event->getUser();

$data['organization'] = $user->getOrganization()->getId();

$event->setData($data);

}
JWT Events (success)
# config/services.yaml

AppEventListenerAuthenticationSuccessListener:

tags:

- {

name: kernel.event_listener, 

event: lexik_jwt_authentication.on_authentication_success,

method: onAuthenticationSuccessResponse

}

# src/EventListener/AuthenticationSuccessListener.php

public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $event) 

{

$data = $event->getData();

$user = $event->getUser();

$data[‘roles'] = $user->getOrganization()->getRoles();

$event->setData($data);

}
React+Redux+Saga+
AntDesign
dvajs/dva - React and redux based framework. 
https://github.com/dvajs/dva
React / Redux / Saga / AntDesig
> Use webpack instead of roadhog.
> Use apollo-fetch for GraphQL calls.
> Use jwt-decode to interact with JWT.
> Use LocalStorage for simple key/values storage.
> Use IndexedDB for encrypted and/or more complex data structures.
> Use Socket-IO + Redis to sync API with ReactJS client.
Tips
Directory Structure
├── package.json
├── src
│   ├── components
│   ├── constants.js
│   ├── index.js
│   ├── models
│   ├── router.js
│   ├── routes
│   └── services
└── webpack.config.js
constants.js
export const API_URL = process.env.API_ENTRY_POINT;
export const GRAPHQL_URL = `${API_URL}/api/graphql`;
export const NOTIFICATION_URL = process.env.NOTIFICATION_URL;
export const NOTIFICATION_ICON = {
info: 'info',
warning: 'exclamation',
error: 'close',
success: 'check'
};
index.js
import dva from 'dva';

import auth from './models/auth';

import local from './models/local';

import ui from './models/ui';
const app = dva({

…

});



# Register global models

app.model(auth);

app.model(local);

app.model(ui);

app.router(require('./router'));

app.start(‘#root');
router.js 1/2
import …

import AuthRoute from './components/Auth/AuthRoute';
export default function RouterConfig({ history, app }) {

const Login = dynamic({

app,

component: () => import('./routes/Login'),

});
const routes = [{

path: '/posts',

models: () => [

import('./models/posts')

],

component: () => import('./routes/Posts'),

}, {
path: '/posts/:id',

models: () => [

import('./models/projects'),

],

component: () => import('./routes/Posts'),

}];
router.js 2/2
return (
<Router history={history}>

<Switch>

<Route exact path="/" render={() => (<Redirect to="/login" />)} />

<Route exact path="/login" component={Login} />

{

routes.map(({ path, onEnter, ...dynamics }, key) => (
<AuthRoute

key={key} exact path={path}

component={dynamic({

app,

...dynamics,

})}

/>

))
}

</Switch>

</Router>

);

}
src/components/Auth/AuthRoute.js
import {Route, Redirect} from "dva/router";

…
class AuthRoute extends Route {
async isTokenValid() {

# Check for token and refresh if not valid 

}
render() {
return (
<Async
promise={this.isTokenValid()}
then={(isValid) => isValid ?
<Route path={this.props.path} component={this.props.component} />
:
<Redirect to={{ pathname: '/login' }}/>
}
/>
);
};
src/models/posts.js 1/3
import {Route, Redirect} from "dva/router";

import * as postService from '../services/base';

import _map from 'lodash/map';

…
export default {

namespace: ‘posts',

state: {

list: [],

total: 0

},

reducers: {

save(state, { payload: { list, total } }) {

return { ...state, list, total};

},
},
src/models/posts.js 2/3
effects: {

*fetch({ payload: { … }, { call, put }) {

let { list, total } = yield select(state => state.posts);

const graphQuery = `{

posts(first: 10) {

edges {

node {

id, _id, title, body,

type {

id, name, machineName

}

}

}

}

}`;
src/models/posts.js 2/3
#  Async call with Promise support.
const posts = yield call(postService.fetch, 'posts', { … });
const list = _map(posts.data.posts.edges, posts => posts.node)
# Action triggering.
yield put({
type: 'save',
payload: {
list,
total,
},
});
Directory Structure
src/
├── components
   ├── Auth
   ├── Generic
   ├── Layout
   └── Posts
      ├── ProjectBase.js
      ├── ProjectEdit.js
      ├── ProjectList.js
      └── ProjectNew.js
Thank you … Questions?

More Related Content

What's hot (20)

Devoir Final dans No Sql Base de donnée avec corrigé
Devoir Final dans No Sql Base de donnée avec corrigéDevoir Final dans No Sql Base de donnée avec corrigé
Devoir Final dans No Sql Base de donnée avec corrigé
RimaDaqch
 
JDBC: Gestion des bases de données en Java
JDBC: Gestion des bases de données en Java JDBC: Gestion des bases de données en Java
JDBC: Gestion des bases de données en Java
Youness Boukouchi
 
Modélisation de données pour MongoDB
Modélisation de données pour MongoDBModélisation de données pour MongoDB
Modélisation de données pour MongoDB
MongoDB
 
Chp5 - Applications Android
Chp5 - Applications AndroidChp5 - Applications Android
Chp5 - Applications Android
Lilia Sfaxi
 
P5 stockage
P5 stockageP5 stockage
P5 stockage
Lilia Sfaxi
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express js
Abdoulaye Dieng
 
Android-Tp4: stockage
Android-Tp4: stockageAndroid-Tp4: stockage
Android-Tp4: stockage
Lilia Sfaxi
 
Introduction à Symfony
Introduction à SymfonyIntroduction à Symfony
Introduction à Symfony
Abdoulaye Dieng
 
Présentation PFE (Conception et développement d'une application web && mobile...
Présentation PFE (Conception et développement d'une application web && mobile...Présentation PFE (Conception et développement d'une application web && mobile...
Présentation PFE (Conception et développement d'une application web && mobile...
Ramzi Noumairi
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)
Mark Proctor
 
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
fisuda
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
현철 조
 
Support Web Services SOAP et RESTful Mr YOUSSFI
Support Web Services SOAP et RESTful Mr YOUSSFISupport Web Services SOAP et RESTful Mr YOUSSFI
Support Web Services SOAP et RESTful Mr YOUSSFI
ENSET, Université Hassan II Casablanca
 
P1 introduction à android
P1 introduction à androidP1 introduction à android
P1 introduction à android
Lilia Sfaxi
 
Les Base de Données NOSQL -Presentation -
Les Base de Données NOSQL -Presentation -Les Base de Données NOSQL -Presentation -
Les Base de Données NOSQL -Presentation -
IliasAEA
 
Présentation de Microsoft Azure
Présentation de Microsoft AzurePrésentation de Microsoft Azure
Présentation de Microsoft Azure
Christophe Peugnet
 
Chp3 - Diagramme de Classes
Chp3 - Diagramme de ClassesChp3 - Diagramme de Classes
Chp3 - Diagramme de Classes
Lilia Sfaxi
 
UML Part1-Introduction Mansouri
UML Part1-Introduction MansouriUML Part1-Introduction Mansouri
UML Part1-Introduction Mansouri
Mansouri Khalifa
 
cours javascript.pptx
cours javascript.pptxcours javascript.pptx
cours javascript.pptx
YaminaGh1
 
Support JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.YoussfiSupport JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.Youssfi
ENSET, Université Hassan II Casablanca
 
Devoir Final dans No Sql Base de donnée avec corrigé
Devoir Final dans No Sql Base de donnée avec corrigéDevoir Final dans No Sql Base de donnée avec corrigé
Devoir Final dans No Sql Base de donnée avec corrigé
RimaDaqch
 
JDBC: Gestion des bases de données en Java
JDBC: Gestion des bases de données en Java JDBC: Gestion des bases de données en Java
JDBC: Gestion des bases de données en Java
Youness Boukouchi
 
Modélisation de données pour MongoDB
Modélisation de données pour MongoDBModélisation de données pour MongoDB
Modélisation de données pour MongoDB
MongoDB
 
Chp5 - Applications Android
Chp5 - Applications AndroidChp5 - Applications Android
Chp5 - Applications Android
Lilia Sfaxi
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express js
Abdoulaye Dieng
 
Android-Tp4: stockage
Android-Tp4: stockageAndroid-Tp4: stockage
Android-Tp4: stockage
Lilia Sfaxi
 
Présentation PFE (Conception et développement d'une application web && mobile...
Présentation PFE (Conception et développement d'une application web && mobile...Présentation PFE (Conception et développement d'une application web && mobile...
Présentation PFE (Conception et développement d'une application web && mobile...
Ramzi Noumairi
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)
Mark Proctor
 
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
NGSIv1 を知っている開発者向けの NGSIv2 の概要 (Orion 3.1.0対応)
fisuda
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
현철 조
 
P1 introduction à android
P1 introduction à androidP1 introduction à android
P1 introduction à android
Lilia Sfaxi
 
Les Base de Données NOSQL -Presentation -
Les Base de Données NOSQL -Presentation -Les Base de Données NOSQL -Presentation -
Les Base de Données NOSQL -Presentation -
IliasAEA
 
Présentation de Microsoft Azure
Présentation de Microsoft AzurePrésentation de Microsoft Azure
Présentation de Microsoft Azure
Christophe Peugnet
 
Chp3 - Diagramme de Classes
Chp3 - Diagramme de ClassesChp3 - Diagramme de Classes
Chp3 - Diagramme de Classes
Lilia Sfaxi
 
UML Part1-Introduction Mansouri
UML Part1-Introduction MansouriUML Part1-Introduction Mansouri
UML Part1-Introduction Mansouri
Mansouri Khalifa
 
cours javascript.pptx
cours javascript.pptxcours javascript.pptx
cours javascript.pptx
YaminaGh1
 

Similar to Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA (20)

Creating a modern web application using Symfony API Platform Atlanta
Creating a modern web application using  Symfony API Platform AtlantaCreating a modern web application using  Symfony API Platform Atlanta
Creating a modern web application using Symfony API Platform Atlanta
Jesus Manuel Olivas
 
Red5 - PHUG Workshops
Red5 - PHUG WorkshopsRed5 - PHUG Workshops
Red5 - PHUG Workshops
Brendan Sera-Shriar
 
High quality ap is with api platform
High quality ap is with api platformHigh quality ap is with api platform
High quality ap is with api platform
Nelson Kopliku
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0
Eugenio Romano
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
James Titcumb
 
Red5workshop 090619073420-phpapp02
Red5workshop 090619073420-phpapp02Red5workshop 090619073420-phpapp02
Red5workshop 090619073420-phpapp02
arghya007
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
Francois Zaninotto
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
Rubyc Slides
 
Phoenix for Rails Devs
Phoenix for Rails DevsPhoenix for Rails Devs
Phoenix for Rails Devs
Diacode
 
Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
Wildan Maulana
 
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
King Foo
 
Symfony2 for Midgard Developers
Symfony2 for Midgard DevelopersSymfony2 for Midgard Developers
Symfony2 for Midgard Developers
Henri Bergius
 
Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
Tatsuhiko Miyagawa
 
Creating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 ComponentsCreating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 Components
Deepak Chandani
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
mirrec
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
Diego Lewin
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
sickill
 
Divide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.jsDivide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.js
Sebastian Springer
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
Antônio Roberto Silva
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
Creating a modern web application using Symfony API Platform Atlanta
Creating a modern web application using  Symfony API Platform AtlantaCreating a modern web application using  Symfony API Platform Atlanta
Creating a modern web application using Symfony API Platform Atlanta
Jesus Manuel Olivas
 
High quality ap is with api platform
High quality ap is with api platformHigh quality ap is with api platform
High quality ap is with api platform
Nelson Kopliku
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0
Eugenio Romano
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
James Titcumb
 
Red5workshop 090619073420-phpapp02
Red5workshop 090619073420-phpapp02Red5workshop 090619073420-phpapp02
Red5workshop 090619073420-phpapp02
arghya007
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
Francois Zaninotto
 
Phoenix for Rails Devs
Phoenix for Rails DevsPhoenix for Rails Devs
Phoenix for Rails Devs
Diacode
 
Exploring Symfony's Code
Exploring Symfony's CodeExploring Symfony's Code
Exploring Symfony's Code
Wildan Maulana
 
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
Building Web Services with Zend Framework (PHP Benelux meeting 20100713 Vliss...
King Foo
 
Symfony2 for Midgard Developers
Symfony2 for Midgard DevelopersSymfony2 for Midgard Developers
Symfony2 for Midgard Developers
Henri Bergius
 
Creating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 ComponentsCreating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 Components
Deepak Chandani
 
Rails Engine | Modular application
Rails Engine | Modular applicationRails Engine | Modular application
Rails Engine | Modular application
mirrec
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
Diego Lewin
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
sickill
 
Divide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.jsDivide and Conquer – Microservices with Node.js
Divide and Conquer – Microservices with Node.js
Sebastian Springer
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
Antônio Roberto Silva
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
Ad

More from Jesus Manuel Olivas (20)

Remix & GraphQL: A match made in heaven with type-safety DX
Remix & GraphQL:  A match made in heaven with type-safety DXRemix & GraphQL:  A match made in heaven with type-safety DX
Remix & GraphQL: A match made in heaven with type-safety DX
Jesus Manuel Olivas
 
Drupal 10 Party GraphQL
Drupal 10 Party GraphQLDrupal 10 Party GraphQL
Drupal 10 Party GraphQL
Jesus Manuel Olivas
 
How to use Drupal to create editorial experiences your content creators will...
How to use Drupal  to create editorial experiences your content creators will...How to use Drupal  to create editorial experiences your content creators will...
How to use Drupal to create editorial experiences your content creators will...
Jesus Manuel Olivas
 
Beyond Static: Building a Dynamic Application with Gatsby
Beyond Static: Building a Dynamic Application with GatsbyBeyond Static: Building a Dynamic Application with Gatsby
Beyond Static: Building a Dynamic Application with Gatsby
Jesus Manuel Olivas
 
Drupal, GraphQL, Views, View Modes and Gatsby for a US Gov site CMS Philly
Drupal, GraphQL, Views, View Modes  and Gatsby for a US Gov site CMS PhillyDrupal, GraphQL, Views, View Modes  and Gatsby for a US Gov site CMS Philly
Drupal, GraphQL, Views, View Modes and Gatsby for a US Gov site CMS Philly
Jesus Manuel Olivas
 
Embracing the modern web using a Headless CMS with GatsbyJS CMS Philly
Embracing the modern web  using a Headless CMS with GatsbyJS CMS PhillyEmbracing the modern web  using a Headless CMS with GatsbyJS CMS Philly
Embracing the modern web using a Headless CMS with GatsbyJS CMS Philly
Jesus Manuel Olivas
 
Embracing the modern web using a Headless CMS with GatsbyJS Stanford
Embracing the modern web using a Headless CMS with GatsbyJS StanfordEmbracing the modern web using a Headless CMS with GatsbyJS Stanford
Embracing the modern web using a Headless CMS with GatsbyJS Stanford
Jesus Manuel Olivas
 
Building a modern application using Symfony API Platform and GatsbyJS PHP QRO
Building a modern application using  Symfony API Platform and GatsbyJS PHP QROBuilding a modern application using  Symfony API Platform and GatsbyJS PHP QRO
Building a modern application using Symfony API Platform and GatsbyJS PHP QRO
Jesus Manuel Olivas
 
Building a dynamic application with GatsbyJS-Tec-Mexicali
Building a dynamic application  with GatsbyJS-Tec-MexicaliBuilding a dynamic application  with GatsbyJS-Tec-Mexicali
Building a dynamic application with GatsbyJS-Tec-Mexicali
Jesus Manuel Olivas
 
Building a modern web application in the cloud partnercon
Building a modern web application in the cloud partnerconBuilding a modern web application in the cloud partnercon
Building a modern web application in the cloud partnercon
Jesus Manuel Olivas
 
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCampEmbracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Jesus Manuel Olivas
 
Blazing fast sites using Blaze, Hybrid CMS NYC
Blazing fast sites using Blaze, Hybrid CMS NYCBlazing fast sites using Blaze, Hybrid CMS NYC
Blazing fast sites using Blaze, Hybrid CMS NYC
Jesus Manuel Olivas
 
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYCEmbracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Jesus Manuel Olivas
 
Writing a slack chatbot seattle
Writing a slack chatbot seattleWriting a slack chatbot seattle
Writing a slack chatbot seattle
Jesus Manuel Olivas
 
Building a Modern Web Application in the Cloud TecNerd
Building a Modern Web Application in the Cloud TecNerdBuilding a Modern Web Application in the Cloud TecNerd
Building a Modern Web Application in the Cloud TecNerd
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era Florida
How to keep Drupal relevant in the Git-based and API-driven CMS era FloridaHow to keep Drupal relevant in the Git-based and API-driven CMS era Florida
How to keep Drupal relevant in the Git-based and API-driven CMS era Florida
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJHow to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
Jesus Manuel Olivas
 
Tools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 EditionTools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 Edition
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCampHow to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
Jesus Manuel Olivas
 
Battle of the CMS DrupalCampLA
Battle of the CMS DrupalCampLABattle of the CMS DrupalCampLA
Battle of the CMS DrupalCampLA
Jesus Manuel Olivas
 
Remix & GraphQL: A match made in heaven with type-safety DX
Remix & GraphQL:  A match made in heaven with type-safety DXRemix & GraphQL:  A match made in heaven with type-safety DX
Remix & GraphQL: A match made in heaven with type-safety DX
Jesus Manuel Olivas
 
How to use Drupal to create editorial experiences your content creators will...
How to use Drupal  to create editorial experiences your content creators will...How to use Drupal  to create editorial experiences your content creators will...
How to use Drupal to create editorial experiences your content creators will...
Jesus Manuel Olivas
 
Beyond Static: Building a Dynamic Application with Gatsby
Beyond Static: Building a Dynamic Application with GatsbyBeyond Static: Building a Dynamic Application with Gatsby
Beyond Static: Building a Dynamic Application with Gatsby
Jesus Manuel Olivas
 
Drupal, GraphQL, Views, View Modes and Gatsby for a US Gov site CMS Philly
Drupal, GraphQL, Views, View Modes  and Gatsby for a US Gov site CMS PhillyDrupal, GraphQL, Views, View Modes  and Gatsby for a US Gov site CMS Philly
Drupal, GraphQL, Views, View Modes and Gatsby for a US Gov site CMS Philly
Jesus Manuel Olivas
 
Embracing the modern web using a Headless CMS with GatsbyJS CMS Philly
Embracing the modern web  using a Headless CMS with GatsbyJS CMS PhillyEmbracing the modern web  using a Headless CMS with GatsbyJS CMS Philly
Embracing the modern web using a Headless CMS with GatsbyJS CMS Philly
Jesus Manuel Olivas
 
Embracing the modern web using a Headless CMS with GatsbyJS Stanford
Embracing the modern web using a Headless CMS with GatsbyJS StanfordEmbracing the modern web using a Headless CMS with GatsbyJS Stanford
Embracing the modern web using a Headless CMS with GatsbyJS Stanford
Jesus Manuel Olivas
 
Building a modern application using Symfony API Platform and GatsbyJS PHP QRO
Building a modern application using  Symfony API Platform and GatsbyJS PHP QROBuilding a modern application using  Symfony API Platform and GatsbyJS PHP QRO
Building a modern application using Symfony API Platform and GatsbyJS PHP QRO
Jesus Manuel Olivas
 
Building a dynamic application with GatsbyJS-Tec-Mexicali
Building a dynamic application  with GatsbyJS-Tec-MexicaliBuilding a dynamic application  with GatsbyJS-Tec-Mexicali
Building a dynamic application with GatsbyJS-Tec-Mexicali
Jesus Manuel Olivas
 
Building a modern web application in the cloud partnercon
Building a modern web application in the cloud partnerconBuilding a modern web application in the cloud partnercon
Building a modern web application in the cloud partnercon
Jesus Manuel Olivas
 
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCampEmbracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Embracing the modern web using Drupal as a Headless CMS with Gatsby BADCamp
Jesus Manuel Olivas
 
Blazing fast sites using Blaze, Hybrid CMS NYC
Blazing fast sites using Blaze, Hybrid CMS NYCBlazing fast sites using Blaze, Hybrid CMS NYC
Blazing fast sites using Blaze, Hybrid CMS NYC
Jesus Manuel Olivas
 
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYCEmbracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Embracing the modern web using Drupal as Headless CMS with GatsbyJS NYC
Jesus Manuel Olivas
 
Building a Modern Web Application in the Cloud TecNerd
Building a Modern Web Application in the Cloud TecNerdBuilding a Modern Web Application in the Cloud TecNerd
Building a Modern Web Application in the Cloud TecNerd
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era Florida
How to keep Drupal relevant in the Git-based and API-driven CMS era FloridaHow to keep Drupal relevant in the Git-based and API-driven CMS era Florida
How to keep Drupal relevant in the Git-based and API-driven CMS era Florida
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJHow to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
How to keep Drupal relevant in the Git-based and API-driven CMS era DrupalCampNJ
Jesus Manuel Olivas
 
Tools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 EditionTools and Projects Dec 2018 Edition
Tools and Projects Dec 2018 Edition
Jesus Manuel Olivas
 
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCampHow to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
How to keep Drupal relevant in the Git-based and API-driven CMS era - BADCamp
Jesus Manuel Olivas
 
Ad

Recently uploaded (20)

If You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FMEIf You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FME
Safe Software
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdfHow Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
Rejig Digital
 
Floods in Valencia: Two FME-Powered Stories of Data Resilience
Floods in Valencia: Two FME-Powered Stories of Data ResilienceFloods in Valencia: Two FME-Powered Stories of Data Resilience
Floods in Valencia: Two FME-Powered Stories of Data Resilience
Safe Software
 
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
angelo60207
 
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Infrassist Technologies Pvt. Ltd.
 
The State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry ReportThe State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry Report
Liveplex
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdfEdge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
Down the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training RoadblocksDown the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training Roadblocks
Rustici Software
 
Ben Blair - Operating Safely in a Vibe Coding World
Ben Blair - Operating Safely in a Vibe Coding WorldBen Blair - Operating Safely in a Vibe Coding World
Ben Blair - Operating Safely in a Vibe Coding World
AWS Chicago
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdfvertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 
Trends Artificial Intelligence - Mary Meeker
Trends Artificial Intelligence - Mary MeekerTrends Artificial Intelligence - Mary Meeker
Trends Artificial Intelligence - Mary Meeker
Clive Dickens
 
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdfcnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
AmirStern2
 
Introduction to Typescript - GDG On Campus EUE
Introduction to Typescript - GDG On Campus EUEIntroduction to Typescript - GDG On Campus EUE
Introduction to Typescript - GDG On Campus EUE
Google Developer Group On Campus European Universities in Egypt
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
Cisco ISE Performance, Scalability and Best Practices.pdf
Cisco ISE Performance, Scalability and Best Practices.pdfCisco ISE Performance, Scalability and Best Practices.pdf
Cisco ISE Performance, Scalability and Best Practices.pdf
superdpz
 
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
Edge AI and Vision Alliance
 
Artificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdfArtificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdf
OnBoard
 
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
Safe Software
 
How to Detect Outliers in IBM SPSS Statistics.pptx
How to Detect Outliers in IBM SPSS Statistics.pptxHow to Detect Outliers in IBM SPSS Statistics.pptx
How to Detect Outliers in IBM SPSS Statistics.pptx
Version 1 Analytics
 
If You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FMEIf You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FME
Safe Software
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdfHow Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
How Advanced Environmental Detection Is Revolutionizing Oil & Gas Safety.pdf
Rejig Digital
 
Floods in Valencia: Two FME-Powered Stories of Data Resilience
Floods in Valencia: Two FME-Powered Stories of Data ResilienceFloods in Valencia: Two FME-Powered Stories of Data Resilience
Floods in Valencia: Two FME-Powered Stories of Data Resilience
Safe Software
 
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
angelo60207
 
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Infrassist Technologies Pvt. Ltd.
 
The State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry ReportThe State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry Report
Liveplex
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdfEdge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
Down the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training RoadblocksDown the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training Roadblocks
Rustici Software
 
Ben Blair - Operating Safely in a Vibe Coding World
Ben Blair - Operating Safely in a Vibe Coding WorldBen Blair - Operating Safely in a Vibe Coding World
Ben Blair - Operating Safely in a Vibe Coding World
AWS Chicago
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdfvertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 
Trends Artificial Intelligence - Mary Meeker
Trends Artificial Intelligence - Mary MeekerTrends Artificial Intelligence - Mary Meeker
Trends Artificial Intelligence - Mary Meeker
Clive Dickens
 
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdfcnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
AmirStern2
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
Cisco ISE Performance, Scalability and Best Practices.pdf
Cisco ISE Performance, Scalability and Best Practices.pdfCisco ISE Performance, Scalability and Best Practices.pdf
Cisco ISE Performance, Scalability and Best Practices.pdf
superdpz
 
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
Edge AI and Vision Alliance
 
Artificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdfArtificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdf
OnBoard
 
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
Safe Software
 
How to Detect Outliers in IBM SPSS Statistics.pptx
How to Detect Outliers in IBM SPSS Statistics.pptxHow to Detect Outliers in IBM SPSS Statistics.pptx
How to Detect Outliers in IBM SPSS Statistics.pptx
Version 1 Analytics
 

Creating a modern web application using Symfony API Platform, ReactJS and Redux DrupalCampLA

  • 1. Creating a modern web application using Symfony API Platform, ReactJS and Redux by Jesus Manuel Olivas / weKnow @jmolivas
  • 2. ● WHO AM I? Jesus Manuel Olivas [email protected] jmolivas jmolivas drupal.org/u/jmolivas jmolivas.weknowinc.com
  • 6. Symfony API Platform / GraphQL  ReactJS / Redux / Saga Ant Design
  • 8. Symfony Flex … a Composer plugin for Symfony > Symfony Flex is a Composer plugin that modifies the behavior of the require, update, and remove composer commands. > Symfony Flex automates the most common tasks of Symfony applications, like installing and removing bundles and other dependencies using recipes defined in a manifest.json file.
  • 11. The API Platform Framework REST and GraphQL framework to build modern API-driven projects https://api-platform.com/
  • 12. Built on the Shoulders of Giants > Extend the framework with thousands of existing Symfony bundles and React components. > The API component includes the Symfony 4 flex, the Doctrine ORM. Client-side components and Admin based on React and a Docker configuration ready to startup your project using one single command. > Reuse all your Symfony, React and Docker skills and benefit of their high quality docs; you are in known territory.
  • 13. The API Platform Components API Schema Admin CRUD
  • 14. Try API-Platform # Clone code repository
 git clone https://github.com/api-platform/api-platform.git
  • 15. Recommendations and adjustments > Update route prefix at api/config/routes/api_platform.yaml file. api_platform:
 …
 prefix: /api > Update admin/.env and client/.env files (change protocol and port). REACT_APP_API_ENTRYPOINT=http://localhost:8080/api
  • 16. Start containers … and grab water, coffee, or a beer. # Start containers ahoy up # Open browser open http://localhost/
  • 17. Add more formats Update api/config/packages/api_platform.yaml adding: formats: jsonld: [‘application/ld+json'] # first one is the default format json: ['application/json'] jsonhal: ['application/hal+json'] xml: ['application/xml', 'text/xml'] yaml: ['application/x-yaml'] csv: ['text/csv'] html: ['text/html']
  • 18. Add Dependencies > Add new entities to api/src/Entity/ directory:
 ahoy console make:entity
 
 > Remove default entity
 api/src/Entity/Greeting.php
  • 23. api/src/Entity/Post.php 1/3 <?php
 namespace AppEntity;
 
 use ApiPlatformCoreAnnotationApiResource;
 use DoctrineORMMapping as ORM;
 use SymfonyComponentValidatorConstraints as Assert; /**
 * @ApiResource
 * @ORMTable(name="post")
 * @ORMEntity
 */ class Post { … }
  • 24. api/src/Entity/Post.php 2/3 /**
 * @ORMId
 * @ORMGeneratedValue(strategy="AUTO")
 * @ORMColumn(type="integer")
 */
 private $id; /**
 * @ORMColumn
 * @AssertNotBlank
 */
 public $title = '';
 /**
 * @ORMColumn * @AssertNotBlank */ public $body = '';
  • 25. api/src/Entity/Post.php 3/3 /** * @ORMManyToOne(targetEntity="PostType") * @ORMJoinColumn(name="post_type_id", referencedColumnName="id", nullable=false) */ public $type; public function getId(): int { return $this->id; }
  • 26. Tracking Database changes # Add dependency ahoy composer require migrations # Execute command(s) ahoy console make:migration ahoy console doctrine:migrations:migrate
  • 27. Add FOSUserBundle # Add dependency composer require friendsofsymfony/user-bundle composer require symfony/swiftmailer-bundle https://symfony.com/doc/current/bundles/FOSUserBundle/index.html https://jolicode.com/blog/do-not-use-fosuserbundle
  • 28. Initialize the project > Drop and Create Database > Execute Migrations > Populate Entities with Data bin/console init Use:
 hautelook/alice-bundle 
 doctrine/data-fixtures
  • 29. Loading Posts using the Browser http://localhost:8080/api/posts http://localhost:8080/api/posts.json http://localhost:8080/api/posts.jsonld http://localhost:8080/api/posts/1 http://localhost:8080/api/posts/1.json
  • 30. Loading Posts using the CLI curl -X GET "http://localhost:8080/api/posts" -H "accept: application/json" curl -X GET "http://localhost:8080/api/posts/1" -H "accept: application/ld+json"
  • 31. ADD Posts from CLI curl -X POST "http://localhost:8080/api/posts" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" -d '{ "title": "Post create from CLI", "body": "body- less", "type": "/api/post_types/1"}'
  • 32. UPDATE and REMOVE Posts from CLI curl -X PUT "http://localhost:8080/api/posts/9" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" -d '{ "title": "Updated from CLI"}' curl -X DELETE "http://localhost:8080/api/posts/10" -H "accept: application/json"
  • 33. Serialization > API Platform allows to specify the which attributes of the resource are exposed during the normalization (read) and denormalization (write) process. It relies on the serialization (and deserialization) groups feature of the Symfony Serializer component. > In addition to groups, you can use any option supported by the Symfony Serializer such as enable_max_depth to limit the serialization depth.
  • 34. Serialization Relations (Post => PostType) 1/2 # api/src/Entity/Post.php & PostType.php * @ApiResource(attributes={ * "normalization_context"={"groups"={"read"}}, * "denormalization_context"={"groups"={"write"}} * })
  • 35. Serialization Relations (Post => PostType) 2/2 # Add use keyword to class use SymfonyComponentSerializerAnnotationGroups; # Add use keyword to properties * @Groups({"read"}) * @Groups({"read", "write"})
  • 37. GraphQL GraphQL offers significantly more flexibility for integrators. Allows you to define in detail the only the data you want. GraphQL lets you replace multiple REST requests with a single call to fetch the data you specify.
  • 38. Add GraphQL To enable GraphQL and GraphiQL interface in your API, simply require the graphql-php package using Composer: composer require webonyx/graphql-php open http://localhost:8080/api/graphql
  • 39. Disable GraphiQL Update api/config/packages/api_platform.yaml adding: api_platform: # ... graphql: graphiql: enabled: false # ...
  • 40. Load resource using GraphQL { post (id:"/api/posts/1") { id, title, body } }
  • 41. Load resource using GraphQL form the CLI curl -X POST -H "Content-Type: application/json" -d '{ "query": "{ post(id:"/api/posts/1") { id, title, body }}" }' http://localhost:8080/api/graphql
  • 42. Load resource relations using GraphQL { post (id:"/api/posts/1") { title, body, type { id, name, } } }
  • 43. Load resource relations using GraphQL form the CLI curl -X POST -H "Content-Type: application/json" -d '{ "query": "{ post(id:"/api/posts/1") { id, title, body, type { id, name } }}" }' http://localhost:8080/api/graphql
  • 44. JWT
  • 45. JWT Dependencies # JWT composer require lexik/jwt-authentication-bundle JWT Refresh
 gesdinet/jwt-refresh-token-bundle
  • 46. JWT Events (create) # config/services.yaml
 AppEventListenerJWTCreatedListener:
 tags:
 - {
 name: kernel.event_listener, 
 event: lexik_jwt_authentication.on_jwt_created,
 method: onJWTCreated
 } 
 # src/EventListener/JWTCreatedListener.php
 public function onJWTCreated(JWTCreatedEvent $event)
 {
 $data = $event->getData();
 $user = $event->getUser();
 $data['organization'] = $user->getOrganization()->getId();
 $event->setData($data);
 }
  • 47. JWT Events (success) # config/services.yaml
 AppEventListenerAuthenticationSuccessListener:
 tags:
 - {
 name: kernel.event_listener, 
 event: lexik_jwt_authentication.on_authentication_success,
 method: onAuthenticationSuccessResponse
 }
 # src/EventListener/AuthenticationSuccessListener.php
 public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $event) 
 {
 $data = $event->getData();
 $user = $event->getUser();
 $data[‘roles'] = $user->getOrganization()->getRoles();
 $event->setData($data);
 }
  • 49. dvajs/dva - React and redux based framework.  https://github.com/dvajs/dva
  • 50. React / Redux / Saga / AntDesig
  • 51. > Use webpack instead of roadhog. > Use apollo-fetch for GraphQL calls. > Use jwt-decode to interact with JWT. > Use LocalStorage for simple key/values storage. > Use IndexedDB for encrypted and/or more complex data structures. > Use Socket-IO + Redis to sync API with ReactJS client. Tips
  • 52. Directory Structure ├── package.json ├── src │   ├── components │   ├── constants.js │   ├── index.js │   ├── models │   ├── router.js │   ├── routes │   └── services └── webpack.config.js
  • 53. constants.js export const API_URL = process.env.API_ENTRY_POINT; export const GRAPHQL_URL = `${API_URL}/api/graphql`; export const NOTIFICATION_URL = process.env.NOTIFICATION_URL; export const NOTIFICATION_ICON = { info: 'info', warning: 'exclamation', error: 'close', success: 'check' };
  • 54. index.js import dva from 'dva';
 import auth from './models/auth';
 import local from './models/local';
 import ui from './models/ui'; const app = dva({
 …
 });
 
 # Register global models
 app.model(auth);
 app.model(local);
 app.model(ui);
 app.router(require('./router'));
 app.start(‘#root');
  • 55. router.js 1/2 import …
 import AuthRoute from './components/Auth/AuthRoute'; export default function RouterConfig({ history, app }) {
 const Login = dynamic({
 app,
 component: () => import('./routes/Login'),
 }); const routes = [{
 path: '/posts',
 models: () => [
 import('./models/posts')
 ],
 component: () => import('./routes/Posts'),
 }, { path: '/posts/:id',
 models: () => [
 import('./models/projects'),
 ],
 component: () => import('./routes/Posts'),
 }];
  • 56. router.js 2/2 return ( <Router history={history}>
 <Switch>
 <Route exact path="/" render={() => (<Redirect to="/login" />)} />
 <Route exact path="/login" component={Login} />
 {
 routes.map(({ path, onEnter, ...dynamics }, key) => ( <AuthRoute
 key={key} exact path={path}
 component={dynamic({
 app,
 ...dynamics,
 })}
 />
 )) }
 </Switch>
 </Router>
 );
 }
  • 57. src/components/Auth/AuthRoute.js import {Route, Redirect} from "dva/router";
 … class AuthRoute extends Route { async isTokenValid() {
 # Check for token and refresh if not valid 
 } render() { return ( <Async promise={this.isTokenValid()} then={(isValid) => isValid ? <Route path={this.props.path} component={this.props.component} /> : <Redirect to={{ pathname: '/login' }}/> } /> ); };
  • 58. src/models/posts.js 1/3 import {Route, Redirect} from "dva/router";
 import * as postService from '../services/base';
 import _map from 'lodash/map';
 … export default {
 namespace: ‘posts',
 state: {
 list: [],
 total: 0
 },
 reducers: {
 save(state, { payload: { list, total } }) {
 return { ...state, list, total};
 }, },
  • 59. src/models/posts.js 2/3 effects: {
 *fetch({ payload: { … }, { call, put }) {
 let { list, total } = yield select(state => state.posts);
 const graphQuery = `{
 posts(first: 10) {
 edges {
 node {
 id, _id, title, body,
 type {
 id, name, machineName
 }
 }
 }
 }
 }`;
  • 60. src/models/posts.js 2/3 #  Async call with Promise support. const posts = yield call(postService.fetch, 'posts', { … }); const list = _map(posts.data.posts.edges, posts => posts.node) # Action triggering. yield put({ type: 'save', payload: { list, total, }, });
  • 61. Directory Structure src/ ├── components    ├── Auth    ├── Generic    ├── Layout    └── Posts       ├── ProjectBase.js       ├── ProjectEdit.js       ├── ProjectList.js       └── ProjectNew.js
  • 62. Thank you … Questions?