Slide 1

Slide 1 text

PRACTICAL API

Slide 2

Slide 2 text

WELCOME

Slide 3

Slide 3 text

API4EZ

Slide 4

Slide 4 text

URBAN ETTER @URBMC ON TWITTER @URBAN ON EZ COMMUNITY SLACK

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

4 PARTS

Slide 7

Slide 7 text

WHAT IS AN API

Slide 8

Slide 8 text

WHY DO I NEED AN API

Slide 9

Slide 9 text

HOW DO I CREATE AN API

Slide 10

Slide 10 text

EZ RICH TEXT

Slide 11

Slide 11 text

EXERCISES

Slide 12

Slide 12 text

EXERCISES > README.md > What to do > Bonus > Hints > Code

Slide 13

Slide 13 text

ABOUT INDIAN PALE ALE

Slide 14

Slide 14 text

INDIAN PALE ALE > High hop content > Tends to have more volume percent > Said to be brewed for long ship journeys to India

Slide 15

Slide 15 text

IPA

Slide 16

Slide 16 text

IPA-API

Slide 17

Slide 17 text

ABOUT BREW DOG

Slide 18

Slide 18 text

PUNK IPA

Slide 19

Slide 19 text

DEAD PONY CLUB (3.8%)

Slide 20

Slide 20 text

SIGGIBRÄU

Slide 21

Slide 21 text

WHAT IS AN API

Slide 22

Slide 22 text

TWITTER API GET https://api.twitter.com/1.1/statuses/show.json? id=21046285714025267

Slide 23

Slide 23 text

EZ PLATFORM REST API { "Content": { "_media-type": "application/vnd.ez.api.ContentInfo+json", "_href": "/api/ezp/v2/content/objects/86", "_remoteId": "73be2a5122ecd6a4a7ad1cef6b0393f1", "_id": 86, "ContentType": { "_media-type": "application/vnd.ez.api.ContentType+json", "_href": "/api/ezp/v2/content/types/18" }, "Name": "Build a better performing site with continuous optimization", "Versions": { "_media-type": "application/vnd.ez.api.VersionList+json", "_href": "/api/ezp/v2/content/objects/86/versions" }, "CurrentVersion": { "_media-type": "application/vnd.ez.api.Version+json", "_href": "/api/ezp/v2/content/objects/86/currentversion" } } }

Slide 24

Slide 24 text

PHP API $contentInfo = $contentService->loadContentInfo($contentId); echo $contentInfo->mainLocationId;

Slide 25

Slide 25 text

PHP API $myKitten = new Cat('Kitty'); $myKitten->lookCute();

Slide 26

Slide 26 text

SQL SELECT id, name, review FROM ipa WHERE id = 57;

Slide 27

Slide 27 text

BASH API ln -s my/source my/target

Slide 28

Slide 28 text

APPLICATION PROGRAMMING INTERFACE

Slide 29

Slide 29 text

INTERFACE TO A PROGRAMM

Slide 30

Slide 30 text

PROGRAMMABLE

Slide 31

Slide 31 text

BUILDING BLOCKS A good API makes it easier to develop a program by providing all the building blocks, which are then put together by the programmer. — Wikipedia

Slide 32

Slide 32 text

SEPARATES INTERFACE AND IMPLEMENTATION

Slide 33

Slide 33 text

SPECIFICATION VS IMPLEMENTATION

Slide 34

Slide 34 text

WHAT VS HOW

Slide 35

Slide 35 text

AN API ONLY SPECIFIES WHAT

Slide 36

Slide 36 text

PHP REPRESENTATIONS > interface: specification > trait: implementation > class: specification + implementation

Slide 37

Slide 37 text

WHO WROTE A CLASS?

Slide 38

Slide 38 text

WE'RE DONE, RIGHT?

Slide 39

Slide 39 text

INTRODUCING DEMO CONTENT

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

CALL TO ACTION EXERCISE 1

Slide 43

Slide 43 text

WHY DO YOU NEED AN API

Slide 44

Slide 44 text

IF YOU'RE BUILDING A SLACK BOT

Slide 45

Slide 45 text

WHY YOU NEED AN API AS A PUBLISHER

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

DIFFERENT REPRESENTATIONS OF YOUR CONTENT

Slide 53

Slide 53 text

PROGRAMMABLE ACCESS TO YOUR CONTENT

Slide 54

Slide 54 text

CONTENT DELIVERY

Slide 55

Slide 55 text

REMEMBERING BUILDING BLOCKS A good API makes it easier to develop a program by providing all the building blocks, which are then put together by the programmer. — Wikipedia

Slide 56

Slide 56 text

BUZZWORD ALARM!

Slide 57

Slide 57 text

API FIRST

Slide 58

Slide 58 text

API AS A PRODUCT

Slide 59

Slide 59 text

HEADLESS CMS

Slide 60

Slide 60 text

BASICALLY THE SAME

Slide 61

Slide 61 text

PROGRAMMABLE ACCESS TO YOUR CONTENT

Slide 62

Slide 62 text

EZ REST API TO DELIVER CONTENT

Slide 63

Slide 63 text

WE'RE DONE, RIGHT?

Slide 64

Slide 64 text

REMEMBER > API specifies What not How > Programmable content delivery

Slide 65

Slide 65 text

My content is an ARTICLE not an EZ CONTENT OBJECT

Slide 66

Slide 66 text

LAYERED APIS

Slide 67

Slide 67 text

MOBILE APP USECASE > Request count matters > Verbosity of response matters

Slide 68

Slide 68 text

HIGH LEVEL API/ DOMAIN API [ { "name": "Punk IPA", "review": 5, "brewery": "Brew Dog", "image": "http://www.ipaapi.io/images/punk-ipa.jpg", }, { "name": "Dead Pony Club", "review": 4.5, "brewery": "Brew Dog", "image": "http://www.ipaapi.io/images/dead-pony-club.jpg" } ]

Slide 69

Slide 69 text

HIGH LEVEL API > Specified for a certain use case > No need to know internals > Not flexible > Needed info with one request > Only one format needs to be supported

Slide 70

Slide 70 text

LOW LEVEL API { "Content": { "_media-type": "application/vnd.ez.api.ContentInfo+json", "_href": "/api/ezp/v2/content/objects/86", "_remoteId": "73be2a5122ecd6a4a7ad1cef6b0393f1", "_id": 86, "ContentType": { "_media-type": "application/vnd.ez.api.ContentType+json", "_href": "/api/ezp/v2/content/types/18" }, "Name": "Build a better performing site with continuous optimization", "Versions": { "_media-type": "application/vnd.ez.api.VersionList+json", "_href": "/api/ezp/v2/content/objects/86/versions" }, "CurrentVersion": { "_media-type": "application/vnd.ez.api.Version+json", "_href": "/api/ezp/v2/content/objects/86/currentversion" } } }

Slide 71

Slide 71 text

LOW LEVEL API > One API for loads of use cases > Knowledge of some internals may be required > Very flexible > Different formats (XML or JSON)

Slide 72

Slide 72 text

LOW LEVEL API ✅

Slide 73

Slide 73 text

LET'S BUILD A DOMAIN API

Slide 74

Slide 74 text

HOW TO BUILD AN API

Slide 75

Slide 75 text

MY CONTENT IS AN ARTICLE AN IPA

Slide 76

Slide 76 text

PHP ENTITY (VALUE OBJECT) class IPA { public $id; public $name; public $review; }

Slide 77

Slide 77 text

ENTITY > Value objects > Service which "loads" value objects > Public attributes > eZ Publish Public API has the same architecture

Slide 78

Slide 78 text

CREATE PHP ENTITIES AS A SERVICE class IpaService { public function loadIpa($contentId) { $content = $contentService->loadContent($contentId); $ipa = new IPA(); $ipa->name = $content->getFieldValue('title')->text; // ... } }

Slide 79

Slide 79 text

CALL TO ACTION EXERCISE 2

Slide 80

Slide 80 text

NOW WE HAVE A NORMALIZED ENTITY

Slide 81

Slide 81 text

CONVERT ENTITY TO NEEDED REPRESENTATION

Slide 82

Slide 82 text

WE'RE DONE, RIGHT?

Slide 83

Slide 83 text

WHAT ABOUT IMAGES

Slide 84

Slide 84 text

NOT POSSIBLE TO SEND ALL DATA IN JSON

Slide 85

Slide 85 text

=> GIVE URL WHERE ADDITIONAL CONTENT CAN BE LOADED

Slide 86

Slide 86 text

IMAGES [ { "name": "Punk IPA", "review": 5, "image": "http://www.ipaapi.io/images/punk-ipa.jpg" }, { "name": "Dead Pony Club", "review": 4.5, "image": "http://www.ipaapi.io/images/dead-pony-club.jpg" } ]

Slide 87

Slide 87 text

CALL TO ACTION EXERCISE 3

Slide 88

Slide 88 text

REQUIREMENT > XML and JSON > Relationship between IPA and Brewery not clear

Slide 89

Slide 89 text

EZ REST API COMPONENT > Rest Controller > Rest Routing > Visitor pattern

Slide 90

Slide 90 text

VISITORS > Main target: Translate object > Visits objects of a graph, therefore a Visitor > Register as visitor with Symfony DIC tag

Slide 91

Slide 91 text

EZ REST VISITOR - BASIC public function visit(Visitor $visitor, Generator $generator, $data) { $generator->startObjectElement('ipa'); $generator->startValueElement('name', $data->name); $generator->endValueElement('name'); $generator->startValueElement('rating', $data->review); $generator->endValueElement('rating'); $generator->endObjectElement('ipa'); }

Slide 92

Slide 92 text

EZ REST VISITOR - MIME && HREF public function visit(Visitor $visitor, Generator $generator, $data) { $mediaType = 'ipa'; $generator->startObjectElement('ipa', $mediaType); $visitor->setHeader('Content-Type', $generator->getMediaType($mediaType)); $generator->startAttribute( 'href', $this->router->generate('ezpublish_rest_ipa', array('contentId' => $data->id)) ); $generator->endAttribute('href'); // ... $generator->endObjectElement('ipa'); }

Slide 93

Slide 93 text

EZ REST CONTROLLER public function ipaAction($contentId) { $service = $this->container->get('app.ipa_service'); $ipa = $service->loadIpa($contentId); return $ipa; }

Slide 94

Slide 94 text

EZ REST CONTROLLER: CACHEDVALUE public function ipaAction($contentId) { $service = $this->container->get('app.ipa_service'); $ipa = $service->loadIpa($contentId); $contentService = $this->container->get('ezpublish.api.service.content'); $locationId = $contentService->loadContentInfo($contentId)->mainLocationId; $cached = new CachedValue($ipa, ['locationId' => $locationId]); return $cached; }

Slide 95

Slide 95 text

CALL TO ACTION EXERCISE 4

Slide 96

Slide 96 text

ADVANTAGES OF EZ REST API > Support of Mime Types > XML or JSON format > Caching > Visitor pattern

Slide 97

Slide 97 text

DISADVANTAGES OF EZ REST API > Some HTTP knowlege (MIME types, headers) needed > Given URL prefix (at least when using legacy) > Verbose visitors

Slide 98

Slide 98 text

EZ RICH TEXT EZ XML TEXT

Slide 99

Slide 99 text

POWERFUL FEATURE OF EZ PLATFORM

Slide 100

Slide 100 text

EZ PUBLISH: EZXMLTEXT EZ PLATFORM: EZRICHTEXT

Slide 101

Slide 101 text

EZ RICH TEXT INTERNAL FORMAT Probably my favorite IPA. Some citrus and grapefruit notes. And just.... awsome. small

Slide 102

Slide 102 text

EZEMBED > means there can be "subviews" which get rendered independently > => override of templates !

Slide 103

Slide 103 text

EZEMBED HARD TO SERIALIZE => XML EVEN IN JSON REPRESENTATION

Slide 104

Slide 104 text

PROBLEM > A JSON representation contains XML tags > => How, not What

Slide 105

Slide 105 text

REPRESENTATIONS RENDERED BY EZ PLATFORM/ EZ PUBLISH

Slide 106

Slide 106 text

PROVIDE LINKS TO REPRESENTATIONS [ { "name": "Punk IPA", "review": 5, "brewery": "Brew Dog", "image": "http://www.ipaapi.io/images/punk-ipa.jpg", "representations": { "html": "http://www.ipaapi.io/ipa/57", "google_amp": "http://www.ipaapi.io/amp/57" } } ]

Slide 107

Slide 107 text

PROBLEMS TO SOLVE > Different representations, different templates > Representations which do not support all content type embeds

Slide 108

Slide 108 text

EZ PLATFORM OVERRIDES CUSTOM REPRESENTATION MATCHER

Slide 109

Slide 109 text

CUSTOM MATCHER content_view: embed: amp_image: template: "AppBundle:Amp:image.html.twig" match: Identifier\ContentType: "image" app.matcher.representation: "amp"

Slide 110

Slide 110 text

CUSTOM MATCHER: CONTROLLER public function ipaAmpAction(Request $request, $contentId) { $ipa = $this->get('app.ipa_service')->getIpa($contentId); $this->get('app.matcher.representation')->setRepresentation('amp') $response = $this->render( 'AppBundle:Amp:ipa.html.twig', [ 'content' => $ipa, ] ); return $response; }

Slide 111

Slide 111 text

CUSTOM MATCHER: MATCHER class Representation extends MultipleValued { private $representationName; public function setRepresentationName($name) { $this->representationName = $name; } public function match(View $view) { return isset($this->values[$this->representationName]); } }

Slide 112

Slide 112 text

RICHTEXT WITH NORMAL IMAGES

Slide 113

Slide 113 text

RICHTEXT WITH OVERRIDDEN IMAGES

Slide 114

Slide 114 text

CALL TO ACTION EXERCISE 5

Slide 115

Slide 115 text

UNSOLVED PROBLEM > New embeddable content type means new override rule for every representation > Lot of empty templates for a new representation

Slide 116

Slide 116 text

EZRICHTEXT OUTPUTS > Different output: xhtml5, xhtml5_edit > Renderer used for different outputs

Slide 117

Slide 117 text

USE CUSTOM RENDERER TO CLEAN OUT UNSUPPORTED TYPES

Slide 118

Slide 118 text

RICHTEXT RENDERER > Priority 0: Link Renderer > Priority 10: Embed Renderer > New Priority 5: Embed Reducer

Slide 119

Slide 119 text

RICHTEXTREDUCER class RichTextReducer extends Render implements Converter { /** * Converts given $xmlDoc into another \DOMDocument object. */ public function convert(DOMDocument $xmlDoc) { $embeds = $xmlDoc->getElementsByTagName('ezembed'); foreach ($embeds as $embed) { $href = $embed->getAttribute('xlink:href'); if (!$this->representation->supportsEmbed($href)) { $embed->parentNode->removeChild($embed); } } return $xmlDoc; } }

Slide 120

Slide 120 text

REGISTER RICHTEXTREDUCER app.richtext.converter.reducer: class: "AppBundle\Service\RichTextReducer" arguments: - "@ezpublish.fieldType.ezrichtext.renderer" tags: - {name: ezpublish.ezrichtext.converter.output.xhtml5, priority: 5}

Slide 121

Slide 121 text

CALL TO ACTION EXERCISE 6

Slide 122

Slide 122 text

TANK YOU @URBMC ON TWITTER @URBAN ON EZ COMMUNITY SLACK