Wer sich sonst immer für Wildfly/Tomcat und JAX-RS für seine REST-API Lösungen entschieden hat wird sich mit Apache Meecrowave sehr schnell zu Hause fühlen. Im Grunde ist es auch nichts anderes als ein Tomcat mit JAX-RS nur dass die Setup-Phase fast komplett entfällt. Für Microservices und schnelle Lösungen hat man in wenigen Minuten eine funktionsfähige REST-API.
Für eine einfache REST-API braucht man die pom.xml, eine Klasse mit einer Main-Methode und einen REST-Endpoint.
@Path("test")
@ApplicationScoped
public class TestController {
@GET
@Produces(MediaType.APPLICATION_JSON)
public TestModel action(){
TestModel model = new TestModel();
model.setId(23);
model.setName("Test");
return model;
}
}
Der Endpoint ist jetzt erreichbar:
http://localhost:8080/test
Der Vorteil bei dieser Lösung ist, dass man sehr einfach ein Docker-Image mit dieser Anwendung erstellen kann, das man dann direkt deployen kann.
Durch das Meecrowave-Maven-Plugin wird eine meecrowave-meecrowave-distribution.zip im Target-Verzeichnis erstellt.
RUN apk --no-cache add bash
EXPOSE 8080
ENTRYPOINT["sh /app/meecrowave.sh start"]
Auch für Test gibt fertige Meecrowave-Packages, die man nutzen kann. Sonst geht natürlich auch einfach JUnit.
Wer sich jetzt fragt ob Spring Boot besser oder schlechter ist.. ich hatte jetzt mit beiden zu tun und am Ende ist beides an sich das Selbe mit ein jeweils anderen Libs. Beides ist für Microservices sehr gut geeignet.
Sobald ein Plugin neue Models/Entities verwendet oder vorhandene erweitert, sollte das Plugin auch einen Controller für die REST-API mitbringen. Nichts ist nerviger als ein Plugin zu testen und nach 2 Minuten abzubrechen, weil das Plugin keine REST-API hat und man alles im Backend des Shops nachpflegen müsste, was man gerne beim Import der Daten aus dem PIM oder ERP schon gerne direkt mit erledigt hätte. Sets und Bundles sind da so ein Fall.
Was nützt es mir Sets und Bundles aus Artikeln im Backend zusammen bauen zu können wie sie im PIM definiert sind und zwar aus den Artikeln, die aus dem PIM Importiert werden? Wieso nicht direkt gleich mit importieren?
Integration sollte immer an erster Stelle stehen, denn oft diese Integration zu schaffen ist oft teuer und man verzichtet lieber auf ein oder zwei Features, wenn man dann nicht wieder selbst Import- und Exportlösungen zusammen stricken muss, die beim Update des Plugin vielleicht wieder hinfällig werden.
Mein 2. Shopware Plugin (also.. das 2. das in den Community-Store soll..) ist jetzt so gut wie fertig. Es fehlen nur noch ein paar Test und Dokumentation.
Das Plugin stellt einen Export der Orders bereit. Im Gegensatz zu den eingebauten Export hat man hier ein paar mehr Möglichkeiten das Aufgabeformat (so lange es XML ist) anzupassen und alles zu automatisieren.
Features:
- XML Formate: nativ, openTRANS 1.0 (eher experimentell), openTRANS 2.1
- automatischer Export direkt nach der Bestellung als Datei in ein lokales Verzeichnis
- automatischer Export als XML in einem JSON Container per Push (getestet mit einem Wildfly 11 und einem RestEasy Endpoint)
- Export bestimmter Orders in ein Verzeichnis per CLI
- Abfrage über die REST-API
- REST-API: Als XML in einem JSON-Container (Liste und einzelnd)
- REST-API: Als XML (einzelnd)
- XSLT-TRansformation, damit ist man im Ausgabeformat nicht eingeschränkt (egal ob mit Automatisch, CLI oder REST-API)
- Für die openTRANS-Formate gibt es verschiedene Einstellung für Buyer-Definition und die Party-Ids
Es ist also ein Plugin was rein auf die Integration von Shopware in vorhandene Bestell-Prozesse mit ERP-Systemen wie SAP ausgelegt ist. Arbeit wirklich gut mit Java Application Servern wie Wirldfly zusammen und auch zum Debuggen ist es sehr praktisch die Bestellungen als XML zu dumpen.
Ein relativ alter Fork des Plugin wird bei https://www.notebookswieneu.de genutzt, um die Bestellungen als openTRANS 1.0 an das SAP-System
zu übermitteln.
Diese Woche werden die letzten Dinge erledigt und dann wird es hoffentlich Anfang nächster Woche für den Store eingereicht.
Es fällt schnell auf, dass wenn man das Array mit den Bildern im Article-Model der REST-API ersetzt, die neuen Bilder nicht die alten ersetzen, sondern nur hinzugefügt werden. Das funktioniert auch super bei den selben Bildern, so das in einigen Fällen (wenn man nicht weiß, ob es neue Bilder sind oder nicht) sich doppelte Bilder im Artikel häufen.
Zum Glück bietet die REST-API den Merge Mode an. Dieser gilt für Bilder und Kategorien.
Man muss nur ein neues Feld in den Artikel einbauen:
Default ist hier false. True als Defaultwert hätte ich persönlich logischer gefunden, bzw. eine Einstellung dafür in den Grundeinstellungen, um den Default-Wert zu ändern.
Oft will man irgendwelche Aufgaben erledigen, nach dem ein Artikel gespeichert wurde. Z.B. kann es sein, dass man diesen Artikel prüfen und zu irgendwas hinzufügen möchte oder auch einfach mit dem Artikel verknüpfte andere Artikel mit updaten muss.
Es gibt ein entsprechendes Event, um auf das Speichern eines Artikel im Backend zu reagieren. Dabei wird ein allgemeines Controller-Event verwendet, wie es für jeden Controller erzeugt wird und gegen die dort aufgerufene Action geprüft.
public static function getSubscribedEvents(){
return [
'Enlight_Controller_Action_PostDispatch_Backend_Article' => 'articleRefresh',
];
}
public function articleRefresh(\Enlight_Event_EventArgs $args){
/** @var $subject \Enlight_Controller_Action */
$subject = $args->getSubject();
$request = $subject->Request();
if ($request->getActionName() === 'save') {
$params = $request->getParams();
//TODO do something
}
}
Nun fehlt noch, dass wir auch Änderungen mit bekommen, wenn ein Artikel über die REST-API geändert wird.
Der Controller ist "Articles" und das Module ist "Api". Also ist unser Event "Enlight_Controller_Action_PostDispatch_Api_Articles". Die Action ändern sich natürlich auch, weil wir bei der REST-API Actions wie PUT und POST haben.
public static function getSubscribedEvents(){
return [
'Enlight_Controller_Action_PostDispatch_Backend_Article' => 'articleRefresh',
'Enlight_Controller_Action_PostDispatch_Api_Articles' => 'articleRefresh',
];
}
public function articleRefresh(\Enlight_Event_EventArgs $args){
/** @var $subject \Enlight_Controller_Action */
$subject = $args->getSubject();
$request = $subject->Request();
if (in_array($request->getActionName(), ['save', 'put', 'post'])) {
$params = $request->getParams();
//TODO do something
}
}
Damit sollte man jede Änderung an einem Artikel mitbekommen.
Das gleiche Prinzip sollte entsprechend auch für alle anderen Controller funktionieren.
Ich habe mich jetzt die letzten 2-3 Monate doch relativ ausführlich mit Shopware beschäftigt. Das erste Projekt das live ging war das Creditfair Fair-Vereinsprogramm. Dafür mussten 2 Plugins geschrieben und einige Theme-Anpassungen vorgenommen werden.
Die Plugin-API mit den Events ist wirklich einfach zu erlernen. Einzig die Suche nach dem passenden Event kann immer etwas länger dauern, wobei am Ende weniger die Frage ist, ob es das richtige Event ist, sondern ob es das beste Event ist. Events für jeden Fall gibt es mehr als genug, wobei die Unterschiede wirklich oft in Feinheiten zu suchen sind.
Nebenbei habe ich als Test ein kleines Plugin geschrieben, das das Kunden-Objekt (wenn denn ein Kunde eingeloggt) ist auch beim Versenden von Forms im Template verfügbar macht. Forms verwenden eine eigene kleine und sehr einfache Template Engine. Für die Erweiterung um den Kunden kommt aber dann Smarty3 zum Einsatz. Damit kann man bei Anfragen über Forms, die nur angemeldeten Kunden zur Verfügung stehen, die Kundendaten direkt zur Email hinzufügen, ohne dass der Kunde es selber tun muss.
Insgesamt macht es viel Spass mit Shopware zu entwickeln.. nur.. nur eine Sache gibt.. die bereitet mir noch Kopfzerbrechen.
STAGING
Mit der 5.3 kann man wenigstens Einkaufwelten exportieren und wieder importieren. Das ist schon mal wirklich eine große Hilfe, da so Designer auf dem lokalen System arbeiten und testen können und man erst dann nach der Freigabe die Einkaufwelten auf das produktive System verschieben kann.
Themes kann auch relativ einfach kopieren. Plugins aus dem Community-Store sollte man so oder so nicht durch ein Staging laufen lassen, sondern auf dem produktiven Server neu installieren und konfigurieren.
Content-Seiten sind der Punkt, wo ich noch am Überlegen bin wie man damit umgehen soll. Hier fehlt eine vergleichbare Import/Export Funktion wie bei den Einkaufwelten.
Ein anderes Thema betrifft Shopware aber auch fast alle anderen Shop-Systeme. Das Problem beginnt damit Produkte, Hersteller, etc in das Shop-System zu bekommen. Denn wenn man keinen winzigen Shop mit 10-50 Artikeln hat, wird man sicher die Produkte aus einem Waren-Wirtschafts-System beziehen wollen. Die REST-API von Shopware ist toll und man kommt schnell zu Ergebnissen. Der CSV-Import ist auch nicht schlecht. Aber das Problem ist, dass man dann immer eine Lösung für Shopware baut. Bei anderen Shops eben für das jeweilige System.
Es gibt wohl kaum Shop-Systeme (oder ich konnte sie nicht finden), die Standard-Formate als Core-Feature lesen oder schreiben können.
Bei der Arbeit dürfte ich nun mit CSV, XML und IDocs aus SAP kämpfen. IDocs sind für den Datenaustausch wirklich nicht toll. Jedenfalls nicht, wenn man die SAP-Welt verlässt. In dem Artikel Warum Sie beim Datenaustausch im E-Commerce auf Standardformate setzen sollten von Daniel Peters trifft es sehr gut gut. Ich stimme da zu 100% zu und er trifft wirklich den Punkt, den ich schon seit Jahren nicht verstehe. Wenn ich ein neues System entwickle, dass mit anderen Systemen kommunizieren und Daten austauschen muss. Warum baue ich mir dann immer wieder ein eigenes Format und nehme mir nicht von Anfang an ein Standard-Format. Damit habe ich auch schon mal eine Art Blaupause, wie man mit dieser Art von Daten umgehen kann und sollte mal ein System ausgewechselt werden, muss ich hoffentlich nicht wieder ein neues proprietäres Format in eine Schnittstelle für mein System umwandeln.
Ich hatte mir ein kleines Plugin geschrieben, dass Bestellungen direkt nach dem Speichern als JSON auf dem Server abgelegt hat. Es war zuerst zur Kontrolle und zum Debuggen auf dem Live-Server da. Es hat nicht lange gedauert und ich hatte auch einen XML-Export und 2 Stunden später auch einen rudimentären [url=]OpenTrans[/url] 1.0 export. Auch wenn der Standard sicher noch nicht zu 100% korrekt umgesetzt ist, habe ich doch schon mal ein Export-Format für Bestellungen, das alles enthält was man braucht, strukturiert ist und auch einfach wieder gelesen werden kann.
Ich werde auf jeden Fall an dem Plugin noch mal weiter rumbauen und vielleicht nochmal OpenTrans 2.1 implementieren.
Ich glaube auch das man einfacher eine OpenTrans zu IDoc Lösung findet, ohne selbst was machen zu müssen, als eine Shopware-internes-Format zu IDoc.
Auch der Import der Produkte... warum kann ich nicht einfach OCI oder BMEcat verwenden, um meinen Shop mit Daten zu befüllen. WWS und andere ERP-Systeme können ja diese Format ausgeben. Die Formate, gerade OCI, sind ja auch sehr verbreitet. Warum kann der Shop diese also nicht nativ lesen und benötigt Zusatzsoftware oder Plugins?
Auf der Roadmap von Shopware-Enterprise steht bei B2B jetzt OCI in der "Unsere Visionen für die Zukunft". Richtiges Punchout muss ja nicht mal sein.
Aber die OCI-XML Daten importieren zu können wäre schon einfach toll und würde an vielen Stellen sehr viel Arbeit und Geld sparen.
Das wohl gerade an einem Import für Kunden aus Drittsystemen gearbeitet wird kommt wohl für mich auch zu spät, aber ist schon mal eine tolle Sache.
Momentan überlege ich einen kleines Plugin zu schreiben, dass BMEcat versteht. Nichts all umfassendes mit User-Data-Extensions und so. Ein einfaches kleines, dass nur dafür sorgt, dass Systeme die BMEcat ausgeben können, grundlegend den Shop mit Produkten befüllen können. Wenn ich dann mal wieder Daten aus einem System in Shopware importieren soll, würde ich einfach die Daten auf BMEcat umbiegen können (mit einer Middleware oder XSLT oder so) und müsste an Shopware nichts mehr ändern. Shopware hätte dann eine stabile Schnittstelle, die nicht nur für mich sondern allgemein genutzt werden kann und sogar ein sehr gut dokumentiertes Format nutzt.
Sich der Welt mit Standard-Formaten als Core-Feature zu öffnen, würde vielen Shop sehr gut tun. ... aber wohl auch einen Markt der sich nur auf das verschieben von Daten zwischen Systemen spezialisiert hat, empfindlich treffen können. Für den normalen Entwickler und seinen Shop wäre es aber wirklich ein großer Vorteil.
Wenn man bei Shopware über die REST-API einen Artikel lädt und dann wieder speichern möchte, kann es dazu kommen, dass ein Fehler auftritt, dass der Preis mit der Id X unbekannt sei. Das scheint wohl so gewollt sein. Deswegen sollte man beim Mappen auf Klassen die Id des Prices aus dem mainDetail des Artikeln einfach unterlassen.
//persist failed if a id is present
@JsonIgnore
private int id = 0;
Hier findet meine Post im Shopware-Forum zu dem Thema
Blog-entries by search-pattern/Tags:
Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?