6. Hamburger MINT-Tag

Am 17. November findet der sechste Hamburger MINT-Tag statt. Klar, dass es an diesem Aktionstag auch einen Workshop in der Bücherhalle Hamburg Volksdorf zu diesem Thema geben wird.

Kids im Grundschulalter haben die Möglichkeit, mit dem LEGO Education WeDo 2.0 Set kleine Roboter aus Klemmbausteinen zu bauen und diese mit einer einfachen, graphischen Programmiersprache auf einem Tablet zu programmieren.

Der Kurs findet von 15 bis 18 Uhr statt. Anmeldungen wie üblich direkt in der Bücherhalle Volksdorf.

LEGO WeDo und Calliope Workshops auf dem Java Forum Nord

Das Java Forum Nord findet dieses Jahr am 6. Oktober 2022 im Hannover Congress Centrum statt. Neben tollen Vorträgen für Java-Enthusiasten (die Programmiersprache, nicht die Insel) wird es auch eine JFN4Kids geben.

Auf zwei Workshops können Kids aus ausgewählten Schulen einen Einblick in die IT bekommen. Für Grundschüler gibt es meinen klassischen LEGO WeDo 2.0 Workshop, für Gymnasiasten einen Calliope-Workshop.

Migration Kickstart-GraphlQL zu Spring Boot GraphQL

Seit Spring Boot 2.7.0 unterstützt das Framework GraphQL mit einer „nativen“ Integration, die auf GraphQL Java basiert. Wer zuvor die Kickstart-Variante genutzt hat, erfährt hier in knappen Zeilen, wie man seine Anwendung migriert.

Konfiguration

Der einfachste Teil. Die Konfigurationsparameter sind nun Teil des Spring-Namensraums. Die beiden wichtigsten Parameter am Besipiel:

KickstartSpring Boot
graphql.servlet.mappingspring.graphql.path
graphiql.mappingspring.graphql.graphiql.path

QueryResolver

In Spring Boot läuft alles über @Controller statt über Resolver und es kommen vermehrt Annotationen zum Einsatz. Hier ein einfaches Beispiel:

// Kickstart

@Component
public class Query implements GraphQLQueryResolver {

    private final EntityManager entityManager;

    public Marktpartner marktpartner(Long id) {
        return entityManager.find(Marktpartner.class, id);
    }

}
// Spring Boot

@Controller
public class Query {

    private final EntityManager entityManager;

    @QueryMapping
    public Marktpartner marktpartner(@Argument Long id) {
        return entityManager.find(Marktpartner.class, id);
    }

}

Wenn im GraphQL-Schema weitere Attribute definiert waren, die nicht im zurückgegebenen Objekt enthalten waren, oder um Assoziationen aufzulösen, wurden weitere Resolver-Klassen geschrieben. In Spring Boot gibt es hierfür das @SchemaMapping:

// Kickstart

@Component
public class MarktpartnerResolver implements GraphQLResolver<Marktpartner> {

    public String getUri(Marktpartner marktpartner) {
        return String.format(URL_VISITENKARTE, marktpartner.getId());
    }


    public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, MarktrollenFilter filter) {
        return repository.find...
    }
}
@Controller
public class MarktpartnerResolver {

    @SchemaMapping(typeName = "Marktpartner", field = "uri")
    public String getUri(Marktpartner marktpartner) {
        return String.format(URL_VISITENKARTE, marktpartner.getId());
    }


    @SchemaMapping(typeName = "Marktpartner", field = "marktrollen")
    public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, @Argument MarktrollenFilter filter) {
        return repository.find...
    }
}

Wichtig ist hierbei, das nur in @Controller-annotierten Klassen nach @QueryMapping oder @SchemaMapping gesucht wird.

Relay-Unterstützung

In Spring Boot gibt es noch keine Unterstützung für Relay. Deshalb ist es notwendig, das Schema anzupassen. Dies führt nach meinem jetzigen Kenntnisstand leider auch dazu, dass Clients angepasst werden müssen, jedenfalls, wenn man erst einmal den einfachsten Weg geht.

// Kickstart

type Query {

    marktpartner(id: ID!) : Marktpartner!

    marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : MarktpartnerConnection @connection(for: "Marktpartner")

}

# Relay.js types:
# ---------------
interface Node {
    id: ID
}

type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: String
    endCursor: String
}

type Marktpartner implements Node {
    id: ID!

    name: String!

    // ...
}
// Spring Boot

type Query {

    marktpartner(id: ID!) : Marktpartner!

    marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : Connection

}

# Relay.js types:
# ---------------

interface Node {
    id: ID
}

type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: String
    endCursor: String
}

type Connection {
    edges: [Edge]
    pageInfo: PageInfo
}

type Edge {
    cursor: String!
    node: Node!
}

type Marktpartner implements Node {
    id: ID!

    name: String!

    // ...
}

Hinzu gekommen sind also die expliziten Typ-Definitionen für Connection und Edge.

Die obige Lösung führt jedoch dazu, dass Anfragen des Clients angepasst werden müssen:

// Kickstart

query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
    marktpartners(first: $first, filter: $filter) {
        edges {
            cursor
            node {
                id
                name

            }
        }
    }
}
// Spring Boot

query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
    marktpartners(first: $first, filter: $filter) {
        edges {
            cursor
            node {
                id
                ... on Marktpartner {
                    name
                }
            }
        }
    }
}

Außerdem wird noch eine TypeResolver-Implementierung benötigt:

// Spring Boot

public class NodeTypeResolver implements TypeResolver {

    @Override
    public GraphQLObjectType getType(TypeResolutionEnvironment env) {
        Object object = env.getObject();
        if (object instanceof Marktpartner) {
            return env.getSchema().getObjectType("Marktpartner");
        }

        throw new UnsupportedOperationException("NodeTypeResolver unvollständig für das Objekt " + object);
    }

}

Testing

Am längsten hat die Umstellung der integrativen Tests gedauert, da ich dazu bisher nur wenige Beispiele gefunden hatte. Das wichtigste dabei: Es wird spring-webflux benötigt, auch wenn die Anwendung selbst gar nicht fluxig ist:

pom.xml (Spring Boot)

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-graphql</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.graphql</groupId>
      <artifactId>spring-graphql-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <scope>test</scope>
    </dependency>

Für Tests gibt es in Spring Boot die Klasse GraphQlTester und davon diverse Unterklassen für verschiedene Einsatzszenarien. Mein integrativer Test sieht nach der Umstellung wie folgt aus::

@Transactional
@SpringBootTest
class QueryIT {


    private WebGraphQlTester tester;

    @Autowired
    private ObjectMapper objectMapper;

    // ...

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    void before() {
        WebTestClient webTestClient = MockMvcWebTestClient.bindToApplicationContext(context)
                .configureClient()
                .baseUrl("/api/graphql")
                .defaultHeaders(headers -> headers.setBasicAuth("test", "test"))
                .build();
        tester = HttpGraphQlTester.create(webTestClient);

        // Testdaten anlegen ...
    }


    @Test
    void findetMarktpartnerUeberNameUndMarktrolle() {
        MarktpartnerFilter filter = MarktpartnerFilter.builder().namensteil("acme").build();
        MarktrollenFilter marktrollenFilter = MarktrollenFilter.builder()
                .marktrollen(List.of(MarktfunktionRolle.LIEFERANT))
                .build();

        ObjectNode variables = objectMapper.createObjectNode();
        variables.set("filter", objectMapper.convertValue(filter, ObjectNode.class));
        variables.set("marktrollen", objectMapper.convertValue(marktrollenFilter, ObjectNode.class));
        variables.put("first", 10L);

        tester.documentName("marktpartners")
                .variable("filter", variables.get("filter"))
                .variable("marktrollen", variables.get("marktrollen"))
                .variable("first", variables.get("first"))
                .execute()
                .path("marktpartners.edges").entityList(EdgeDummy.class).hasSize(1)
                .path("marktpartners.edges[0].node.name").entity(String.class).isEqualTo("ACME Energie GmbH")
        ;
    }
}

Zunächst wird also ein WebTestClient erzeugt und konfiguriert und anschließend ein HttpGraphQlTester. Dieser wird dann im eigentlich Test verwendet, um einen GraphQL-Aufruf durchzuführen. Wird wie oben eine documentName("marktpartners") angegeben, dann sucht das System die Datei resources/graphql-test/marktpartners.graphql. Alternativ kann mit der Methode document die GraphQL-Anfrage als String übergeben werden.

Mit execute wird die Anfrage gesendet und anschließend das Ergebnis geprüft. Hier kommen die path-Aufrufe zum Einsatz und Standardvergleichsmethoden wie hasSize oder isEqualTo.

Stolperfallen und andere Anomalitäten

Kleine Sammlung von Inkompatibilitäten zum Verhalten von Kickstart-GraphQL:

  • Verwende List statt Set (bei Set<Enumtyp> gab es Exeptions, dass auf ein Property nicht zugegriffen werden kann)
  • Bean-Standard für Rückgabe-DTOs einhalten, also Methoden nicht edges() benennen sondern getEdges()

Workshops 2022

Auch 2022 wird es wieder meine beliebten Kurse zum Bauen und Programmieren kleiner Roboter mit Klemmbausteinen geben. Nicht nur mit dem bekannten LEGO Education WeDo 2.0, sondern dieses Jahr auch erstmals mit dem Apitor Robot X, ein Robotic-Set von OpenBrickSource mit alternativen (aber kompatiblen) Klemmbausteinen (für die Insider: Die Steine sind von Gobricks).

Der Apitor wendet sich an etwas ältere Kinder. Mit der zum Set zugehörigen App kommen Bauanleitungen für zwölf verschiedene Konstruktionen, vom Roboter, über Rennwagen und Dinosaurier zum E-Piano, Geige und noch weiteren Modellen.

Und wie jedes Jahr gibt es auch 2022 wieder eine Code Week (vom 8. bis 23. Oktober). Freut euch auch auf den Digitaltag am 24. Juni und den Hamburger MINT-Tag am 17. November.

Termine „LEGO-Roboter bauen und programmieren“

Alle Veranstaltungen finden in der Bücherhalle Hamburg-Volksdorf statt. Anmeldungen vor Ort.

  • Sonnabend, 16. April 2022, 10 – 13 Uhr
  • Mittwoch, 25. Mai 2022, 15 – 18 Uhr
  • Freitag, 24. Juni 2022, 15 – 18 Uhr (Digitaltag)
  • Sonnabend, 6. August 2022, 10 – 13 Uhr
  • Oktober, Code Week
  • Sonnabend, 10. Dezember 2022, 10 – 13 Uhr

Termine „Apitor Robot X: Klemmbausteinroboter programmieren“

Alle Veranstaltungen finden in der Bücherhalle Hamburg-Volksdorf statt. Anmeldungen vor Ort.

  • Sonnabend, 28. Mai 2022, 10 – 13 Uhr
  • Sonnabend, 9. Juli 2022, 10 – 13 Uhr
  • Oktober, Code Week

Moritz setzt Roboter in Marsch

Das ist die Überschrift eines Artikels in der Kinderzeitung EXTRA im Weser Kurier vom 9. November 2021. In dem Artikel erzählt uns Moritz (einer meiner Workshop-Teilnehmer), wie einfach es war, einen Roboter aus LEGO-Bausteinen zu bauen und mit einem Tablett zu programmieren. Der Artikel erschien wortgleich in dieser Woche auch in anderen Zeitungen, z. B. in der Aachener Zeitung.

Zeitungsausschnitt aus dem Weser Kurier vom 9.11.2021.

Und auch erst heute bin ich auf den Beitrag der Mopo vom 10. Oktober aufmerksam geworden.

Code Week 2021 – Auftaktveranstaltung

Am vergangangen Sonnabend, den 9. Oktober 2021 fand die Auftaktveranstaltung der Code Week Hamburg in der Zentralbibliothek am Hühnerposten statt. Mit der Kids4IT waren wir mit dem beliebten Workshop „Roboter bauen mit LEGO Wedo“ vor Ort und online mit dem Workshop „App programmieren mit dem AppInventor“ dabei.

Über die Auftaktveranstaltung berichtete am Abend der NDR im Hamburg Journal sowie diverse Print- und Online-Medien, z. B. Heise oder die Süddeutsche Zeitung.

Die Code Week läuft noch bis zum 24. Oktober mit vielen interessanten Workshops weiter. Am 23.10. gibt es einen weiteren LEGO-Workshop unter der Veranstaltungsreihe. Diese ist, genauso wie die Workshops am 12. und 16. Oktober, leider bereits ausgebucht.

Siehe auch: Moritz setzt Roboter in Marsch.

Code Week 2021

Auch in diesem Jahr gibt es wieder die europaweite CodeWeek. Und wie in jedem .Jahr gibt es auch dieses Jahr wieder die Möglichkeit, mit LEGO kleine Roboter zu bauen und zu programmieren. Alles was ihr dafür benötigt ist Spaß an der Technik und ein bischen Kreativität! Alles andere stelle ich als Veranstalter zur Verfügung.

Der Workshop für Mädchen und Jungen im Alter von acht bis zehn Jahren findet (wie auch schon im vorletzten Jahr) in den Räumen der Bücherhalle Hamburg Volksdorf statt. Aufgrund der Hygenieanforderungen leider nur mit halber Teilnehmerzahl, Maske und nur für genesene, geimpfte oder getestet Teilnehmer:innen.

Die Anmeldung erfolgt vor Ort in der Bücherhalle. Bitte kommt nur, wenn ihr auch eine Bestätigung bekommen hat. Beim letzten Mal sind viele ohne Anmeldung gekommen und das gab natürlich viele enttäuschte Kinderaugen…

Fehlt noch etwas wichtiges? Ach ja, der Termin:

Sa. 23. Oktober 2021 von 10 bis 13 Uhr

CodeWeek 2021

LEGO Workshops 2021

Im ersten Halbjahr sind aufgrund der Corona-Pandemie die Workshops in der Bücherhalle Hamburg leider ausgefallen. Jetzt nach den Sommerferien sind Präsenz-Workshops unter Auflagen wieder möglich (halbe Teilnehmerzahl, Mund-Nasen-Schutz, genesen, geimpft, oder negativ getestet).

Die nächsten Workshops Lego-Roboter bauen und programieren finden an folgenden Terminen statt:

  • Dienstag, 12. Oktober 2021 von 14 bis 17 Uhr
  • Sonnabend, 16. Oktober 2021 von 10 bis 13 Uhr
  • Sonnabend, 23. Oktober 2021 von 10 bis 13 Uhr (im Rahmen der CodeWeek 2021)
  • Sonnabend, 27. November 2021 von 10 bis 13 Uhr

Auf den Workshops haben Kinder im alter von acht bis zehn Jahren die Möglichkeit, mit LEGO Education WeDo 2.0 kleine Roboter zu bauen und zu programmieren. Vorraussetzungen für die Teilnahme: Spaß an Technik und Kreativität! Alles weitere wird von mir zu den Workshops mitgebracht (und nein, ihr könnt das LEGO leider nicht behalten…)

Anmeldungen zu den Workshops wie üblich direkt in der Bücherhalle Volksdorf. Schaut dort unbedingt vorbei, denn meine Workshops sind so beliebt, dass die Bücherhalle keine Werbung mehr dafür macht – sonst gibt es leider zu viele enttäuschte Kinderaugen…

LEGO Workshop am 6.6. entfällt / Workshops am 1. und 8.8. finden statt!

Aufgrund der noch gelten Einschränkungen kann der LEGO Workshop am 6. Juni 2020 nicht stattfinden.

Aber die gute Nachricht: Der Workshop am 8. August findet – unter Auflagen – statt! Da jedoch nur maximal fünf Kinder am Kurs teilnehmen können (keine Team-Arbeit), versuche ich derzeit zusammen mit der Bücherhalle Volksdorf noch einen zweiten Termin zu organisieren.

Update: Und dieser Termin ist gefunden: Eine Woche vorher, am 1. August 2020, wie üblich von 10 bis 13 Uhr.

Die Platzvergabe wird wieder über die Bücherhalle erfolgen. Für die Teilnahme bekommt jedes Kind von mir ein paar Baumwollhandschuhe und einen speziellen Stift zur Bedienung des Tablets. Weitere Auflagen seitens der Bücherhalle sind einzuhalten.

Vorankündigung: Auch die Codeweek im Herbst wird stattfinden (10. bis 25. Oktober)! Derzeit sind wir in den Planungen dafür.