# Datenbank mit REST API



## matze86 (1. Dez 2022)

Hallo, wie mir freundlicherweise schon im anderen Thread der Hinweis gegeben wurde,  das "vor" einer Datenbank eine REST-API muss.

Ich habe mich schon ein bisschen schlau gemacht (die REST-API greift auf die Datenbank zu und holt sich so die Daten), aber bevor ich in falsche Richtungen mich orientiere, habe ich mal 2 Fragen.

Kann man eine REST-API selbst bauen (Java, Python)? Und wenn ja gibt es (vielleicht deutsche) Anleitungen dazu?

Ziel ist so etwas auf einen eigenen Linux-Server bzw einen Linux-Server VPS-Server zu installieren.


----------



## KonradN (1. Dez 2022)

matze86 hat gesagt.:


> Kann man eine REST-API selbst bauen (Java, Python)?


Ja, das ist kein Thema und sogar relativ einfach möglich.



matze86 hat gesagt.:


> Und wenn ja gibt es (vielleicht deutsche) Anleitungen dazu?


Ich kenne vor allem Englische Anleitungen. Man kann sich da z.B. Spring Boot oder Quarkus ansehen. (Und da auch mal nach Deutschen Anleitungen suchen. Sollten aber nicht zu alt sein, da sich beide Frameworks zügig weiter entwickeln.)


matze86 hat gesagt.:


> Ziel ist so etwas auf einen eigenen Linux-Server bzw einen Linux-Server VPS-Server zu installieren.


Das geht dann ganz ohne Probleme.


----------



## matze86 (1. Dez 2022)

OK, das hört siech für mich schon mal vielversprechend an, nur das ich Spring Boot und Quarkus noch nie gehört habe.
Braucht man das unbedingt?


----------



## KonradN (1. Dez 2022)

Es vereinfacht alles deutlich, wenn man die Kernfunktionalität nicht selbst erstellen muss. Mit diesen Frameworks muss man nur noch sehr wenig machen.

Ich habe mal kurt geschaut und z.B. https://tschutschu.de/resources/tschutschu/docs/SS2019/SS2019_T07_Wolf_Manuel_Studienarbeit.pdf gefunden. ZU der Qualität kann ich nichts sagen, aber ggf. hilft das etwas für einen Einstieg. (Ich habe es mir nicht angesehen - es gab nur ein kleinen Blick ins Inhaltsverzeichnis)


----------



## matze86 (3. Dez 2022)

Bisher bin ich der Anleitung gefolgt 


KonradN hat gesagt.:


> Ich habe mal kurt geschaut und z.B. https://tschutschu.de/resources/tschutschu/docs/SS2019/SS2019_T07_Wolf_Manuel_Studienarbeit.pdf gefunden.


und habe darüber hinaus noch weitere Video-Tutorial angeschaut.

Jetzt bin ich soweit, das ich zu erste Test's komme, doch leider gibt er ein Fehler aus.

```
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class
```
 Das heißt ich muss eine Datenbanktabelle anlegen.

Aber zum generellen testen möchte ich es ohne Datenbank machen. Geht das überhaupt?


----------



## Jw456 (3. Dez 2022)

matze86 hat gesagt.:


> Aber zum generellen testen möchte ich es ohne Datenbank machen. Geht das überhaupt?


Du könntest die _AutoConfiguration von Spring erstmals deaktivieren zum testen.
Dazu in den application.properties _


```
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
```

setzen.


----------



## matze86 (3. Dez 2022)

Da kommt genau der gleiche Fehler.


----------



## matze86 (3. Dez 2022)

Selbst mit einer existierenden Datenbank mit den Zeilen 

```
spring.datasource.url=jdbc:mysql://ipzudatenbank:3306/testdatenbank
spring.datasource.username=xxx
spring.datasource.password=xxx
spring.jpa.hibernate.ddl-auto=update
```

meldet der Compiler:

```
Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
    If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
    If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
```


----------



## KonradN (3. Dez 2022)

matze86 hat gesagt.:


> Reason: Failed to determine a suitable driver class


Du hast den mysql Treiber vermutlich nicht mit drin.


----------



## matze86 (3. Dez 2022)

Ich glaube zu wissen diesen bei spring boot  initializr mit angegeben zu haben.

Wie kann man so etwas prüfen?
Edit: so sieht meine pom.xml aus:


```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>de.resttest</groupId>
    <artifactId>matze</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>matze</name>
    <description>das ist ein test fuer rest</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
```
Nach dem Ausführen wird in der Zeile 5 (<parent>) eine Fehlermeldung angezeigt mit unzähligen Einträgen.


----------



## KonradN (3. Dez 2022)

Hast du eine Abhängigkeit zu MySQL im Ptojekt? In Maven wäre es etwas wie:
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.31</version>
</dependency>


----------



## matze86 (3. Dez 2022)

In der pom.xml?


----------



## KonradN (3. Dez 2022)

matze86 hat gesagt.:


> In der pom.xml?


Ja


----------



## yfons123 (3. Dez 2022)

KonradN hat gesagt.:


> Ja


Steht ja auch in seiner pom drin


Im Maven Repository fidnest du das was du bei den dependencies rein schreiben musst und  das wäre das da


			https://mvnrepository.com/artifact/com.mysql/mysql-connector-j/8.0.31
		

aber du hast 

```
<dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
```


----------



## matze86 (3. Dez 2022)

Supi, das hat schon mal funktioniert. Ich habe es 1:1 aus dem spring boot übernommen bzw war schon da.


----------



## yfons123 (3. Dez 2022)

ich habe keinerlei ahnung von spring oder spring projekten


----------



## matze86 (7. Dez 2022)

Jetzt habe ich viele Anleitungen sorgfältig durchgearbeitet,z.B. auch diese, Das mit den Ausgaben von allen Daten und eins hinzufügen klappt schon mal ohne Probleme.

Jetzt wollte ich in der Klasse Controller eine Methode hinzufügen, welche ein bestimmter Name oder nur eine bestimmte id ausgibt.
Leider klappt das noch nicht so wie ich mir das vorstelle.
Ich habe eine Klasse "User" erstellt, was name und ort beinhaltet, inklusive den Methoden set- und getter.
Dann eine Klasse UserRebo, die als interface von CrudRepository dient (was kann man noch hier eintragen?).
Und eine Klasse ControllerUser, welche beim Aufruf über eine url angesteuert wird und die "GetMapping" - Methoden ausgewertet werden.

Nun möchte ich alles erweitern, so das man entweder nach einer id oder einen Namen sucht und ausgeben lässt.

Aufrufen möchte ich die letzte Methode im controller "getID" 
Postman gibt mir einen Fehler wenn ich "localhost:8082/api/user/2" eingebe.

Die id 2 gibt es wenn ich "all" ausgebe sehe ich es.
Hier mal  die Klassen damit ihr wisst, was ich bis jetzt gemacht habe.


```
@Entity
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String name;
    private String ort;

    public void setID(Long id) {
        this.id = id;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
  public void setOrt(String ort) {
      this.ort = ort;
  }
 
  public Long getID() {
      return this.id;
  }
 
  public String getName() {
      return this.name;
  }
 
  public String getOrt() {
      return this.ort;
  } 

}
```


```
public interface UserRepo extends CrudRepository<User, Long>{

    List<User> findByName(String lastName);
    User findById(long id);
    
}
```


```
@Controller
@RequestMapping("api") //der Pfad nach der url:port also url:port/api    -- name kann beliebeig sein
public class ControllerUser{
    // Dies bedeutet, die Bean namens userRepository zu erhalten
    // Wird von Spring automatisch generiert, wir werden es verwenden, um die Daten zu verarbeiten   
    @Autowired
    private UserRepo userRepository;
    
    @PostMapping("/add") //nur an post -Anfragen  also url:port/api/add
    // @ResponseBody bedeutet, dass der zurückgegebene String die Antwort ist, kein Ansichtsname
    // @RequestParam bedeutet, dass es sich um einen Parameter aus der GET- oder POST-Anfrage handelt
    public @ResponseBody String addNewUser (@RequestParam String name, @RequestParam String ort) {
        User n = new User();
        n.setName(name);
        n.setOrt(ort);
        userRepository.save(n);
        return "Saved";
    }
    
    @GetMapping("/all") //nur anzeigen -Anfragen  also url:port/api/all
    public @ResponseBody Iterable<User> getAllUsers() {
    // Dies gibt ein JSON oder XML mit den Benutzern zurück
    return userRepository.findAll();
    }
    
    //die besagt Methode funktionier so leider nicht,
    @GetMapping("user/{id}")
    public Optional<User> getID(@PathVariable Long id) {
        return userRepository.findById(id);
    }
        
        
        
}
```
Ich wäre für paar Tipps sehr dankbar.


----------



## KonradN (7. Dez 2022)

matze86 hat gesagt.:


> Postman gibt mir einen Fehler wenn ich "localhost:8082/api/user/2" eingebe.


Wie war das mit meinem Auto? Mein Auto gibt mir einen Fehler. Kannst Du mir sagen, was kaputt ist?

Was ist denn so schwer daran, einfach einmal genau zu sagen, was Du zurück bekommst? Die Response Codes haben alle eine Bedeutung und die kann man durchaus mit angeben.

Ansonsten fällt mir auf, dass Du in den Mappings nicht einheitlich mit den / arbeitest. Ich habe eigentlich immer, dass ich mit / starte. Sprich:
`@GetMapping("/user/{id}")`

Ob das weggelassen werden kann, kann ich im Augenblick nicht sagen, da ich mir das im Detail so nicht angesehen habe. (Für mich startet man mit einem / und gut ist es - damit bin ich bisher sehr gut gefahren. Und ich werde es jetzt nicht ausprobieren, ob es auch anders geht.)

Und bitte: Fang nicht mit Abkürzungen an! Das ist ein UserRepository und nicht UserRepo oder so! Und gibt Variablen vernünftige Bezeichner! n ist kein vernünftiger Bezeichner. Zumal n für einen User? Das kann der createdUser sein - dann ist klar: In der Variable ist der User drin, der erzeugt wurde!


----------



## matze86 (7. Dez 2022)

Also mit dem "/" ist es egal, habe es gerade getestet, aber werde mir angewöhnen es immer mit "/" zu machen.
Postman gibt mir aus:

```
{
    "timestamp": "2022-12-07T12:17:30.612+00:00",
    "status": 404,
    "error": "Not Found",
    "path": "/api/user/2"
}
```


----------



## matze86 (8. Dez 2022)

So ich habe jetzt nochmal alles "durchstudiert", jetzt habe ich die Methoden "put", "delete" und "get" erstellt bzw. überarbeitet.
Jetzt funktioniert es wie es soll.
Alle Methoden funktionieren. Die Frage ist ob es vom Code sauber ist.
Hier erstmal der Controller:

```
@Controller
@RequestMapping("/api") //der Pfad nach der url:port also url:port/api    -- name kann beliebeig sein
public class ControllerUser{
    @Autowired
    private UserRepo userRepository;
    
    @PostMapping("/add")
    public @ResponseBody String addNewUser (@RequestParam String name, @RequestParam String ort) {
        User user = new User();
        user.setName(name);
        user.setOrt(ort);
        userRepository.save(user);
        return "Saved";
    }
    
    @GetMapping("/all")
    public @ResponseBody Iterable<User> getAllUsers () {
        return userRepository.findAll();
    }
    

    //hier wird explizit die ID als Parameter angegeben
    @GetMapping("/user")
     public @ResponseBody Optional<User> nameSearch(@RequestParam Long id) {
            return userRepository.findById(id);
      }
    
    //die ID wird an die URL gehängt
    @GetMapping("/user/{id}")
     public @ResponseBody Optional<User> idSearch(@PathVariable Long id) {
            return userRepository.findById(id);
    }
    
    //ein Eintrag löschen mit dem Parameter ID
    @DeleteMapping("/del")
     public @ResponseBody String loeschen(@RequestParam Long id) {
        userRepository.deleteById(id);
        return "gelöscht";     
    }
    
    //einen Eintrag verändern
    @PutMapping("/put")
     public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
        User user = new User();
        //gesetzt wird die übergebene ID und den Ort
        user.setID(id);
        user.setOrt(ort);
        //hier wird der Name zurückgegeben
        String name = userRepository.findById(id).get().getName();
        //den Namen setzen
        user.setName(name);
        //und speichern
        userRepository.save(user);
        return "erfolgreich";
    }
    
    //hier wird explizit nach dem Namen gesuch und wiedergegeben
    @GetMapping("/einzelausgabe")
     public @ResponseBody List<User> einzel(@RequestParam String name) {
            return userRepository.findByName(name);
      }     
}
```

Was mir noch für Fragen aufwerfen ist, das es viele Tutorial's gibt und alle unterschiedliche Controller mit verschiedenen Methoden  haben wie z.B. ResponseEntity.

Mir stellt sich die Frage was braucht man wann und was wirklich?
Oder kann man mit meinen Controller "leben" der alles beinhaltet?


----------



## Oneixee5 (8. Dez 2022)

Sauber ist es eigentlich nicht. User ist eine Entity, es ist ein Antipattern eine Entity aus einem Rest-Endpunkt zurückzugeben. Man würde ein UserDTO erstellen und dieses zurückgeben.
Der Hintergrund ist: Stell dir vor jemand erweitert User und schreibt da ein Feld rein, welches schutzwürdig ist, z.B.: sexuelle Orientierung. Jetzt gibt dein Rest-Endpunkt automatische diese Daten weiter. Das sollte nicht passieren, auch wenn die Daten nicht direkt in deiner Programmoberfläche oder Webseite sichtbar sind, können sie trotzdem ausgelesen werden. Daher erstellt man ein DTO-Objekt, welches nur die Daten enthält, welche der Endpunkt zurückgeben soll. Auch wenn die Daten im Moment identisch sind. Programme werden sich aber mit der Zeit verändern.
Eine vernünftige IDE(-Einstellung) würde dich auch automatisch auf das Problem hinweisen. Es empfiehlt sich immer die statische Codeanalyse einzuschalten/installieren, z.B.: Sonarlint finde ich ganz gut für Einsteiger.


----------



## Oneixee5 (8. Dez 2022)

Put macht mir auch Schwierigkeiten:

```
//einen Eintrag verändern
    @PutMapping("/put")
     public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
        User user = new User();
        //gesetzt wird die übergebene ID und den Ort
        user.setID(id);
        user.setOrt(ort);
        //hier wird der Name zurückgegeben
        String name = userRepository.findById(id).get().getName();
        //den Namen setzen
        user.setName(name);
        //und speichern
        userRepository.save(user);
        return "erfolgreich";
    }
```
Ich würde es eher so schreiben:

```
//einen Eintrag verändern
    @PutMapping("/put")
    @Transactional
     public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
        User user = userRepository.findById(id).orElseThrow(...);
        user.setOrt(ort);
        //und speichern
        userRepository.save(user); // das sollte gar nicht nötig sein, weglassen
        return "erfolgreich";
    }
```
Statt "erfolgreich" geben wir eigentlich immer das vollständige Object zurück. Es können sich zwischenzeitlich noch weiter Felder geändert haben. So kann man sein Programm aktualisieren.


----------



## matze86 (10. Dez 2022)

Oneixee5 hat gesagt.:


> Sauber ist es eigentlich nicht. User ist eine Entity, es ist ein Antipattern eine Entity aus einem Rest-Endpunkt zurückzugeben. Man würde ein UserDTO erstellen und dieses zurückgeben.
> Der Hintergrund ist: Stell dir vor jemand erweitert User und schreibt da ein Feld rein, welches schutzwürdig ist, z.B.: sexuelle Orientierung. Jetzt gibt dein Rest-Endpunkt automatische diese Daten weiter. Das sollte nicht passieren, auch wenn die Daten nicht direkt in deiner Programmoberfläche oder Webseite sichtbar sind, können sie trotzdem ausgelesen werden. Daher erstellt man ein DTO-Objekt, welches nur die Daten enthält, welche der Endpunkt zurückgeben soll. Auch wenn die Daten im Moment identisch sind. Programme werden sich aber mit der Zeit verändern.
> Eine vernünftige IDE(-Einstellung) würde dich auch automatisch auf das Problem hinweisen. Es empfiehlt sich immer die statische Codeanalyse einzuschalten/installieren, z.B.: Sonarlint finde ich ganz gut für Einsteiger.



Was heißt das jetzt genau? Wie sollte ich vorgehen? Was ist ein DTO-Objekt? Vielleicht kannst du dazu ein Schema verlinken was aufzeigt wie man es richtig macht.


----------



## Oneixee5 (10. Dez 2022)

matze86 hat gesagt.:


> Vielleicht kannst du dazu ein Schema verlinken was aufzeigt wie man es richtig macht.





			https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application


----------



## matze86 (12. Dez 2022)

Danke, ich versuche mich da mal durchzuarbeiten.


----------



## temi (12. Dez 2022)

matze86 hat gesagt.:


> Was ist ein DTO-Objekt?


Data Transfer Object


----------



## matze86 (24. Dez 2022)

Oneixee5 hat gesagt.:


> https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application


Ich habe mir mal die Seite angeschaut, versucht es zu verstehen. Aber leider kommen mehr Fragen auf als Antworten.
Ich weiß nicht mal wie ich den Code verstehen soll, wo soll er hin, wie binde ich mein vorhandenes Rest-Projekt ein?
Was macht die Klasse 
	
	
	
	





```
PostDto
```
 u.s.w. Leider habe ich im Netz auch nicht so viel gesehen, was mich weiter bringt.


----------



## Oneixee5 (24. Dez 2022)

matze86 hat gesagt.:


> Ich habe mir mal die Seite angeschaut, versucht es zu verstehen. Aber leider kommen mehr Fragen auf als Antworten.
> Ich weiß nicht mal wie ich den Code verstehen soll, wo soll er hin, wie binde ich mein vorhandenes Rest-Projekt ein?
> Was macht die Klasse
> 
> ...


In dem Artikel gibt es einen Link zu Github, da kann man sich den fertigen Code anschauen.


----------



## KonradN (24. Dez 2022)

Also das Beispiel hat eine Entity Post und man will nun nicht dieses Entity raus geben sondern nur ein modifiziertes PostDTO.
Daher braucht man nun eunen Mapper, der aus einer Post Instanz eine PostDTO Instanz macht.

Das ist alles. Und das kannst Du 1:1 umwandeln. Dazu "Post" durch den Namen deiner Entity ersetzen.


----------



## matze86 (24. Dez 2022)

Alles gut und schön, aber ich würde gerne wissen wie das ganze im Prinzip arbeitet, also auch die einzelnen Methoden etc. 
Ich wünschte mir in den Anleitungen steht über jede Method und Klasse eine kleine Beschreibung. Es wird leider immer alles im Groben beschrieben.


----------



## mihe7 (24. Dez 2022)

matze86 hat gesagt.:


> aber ich würde gerne wissen wie das ganze im Prinzip arbeitet, also auch die einzelnen Methoden etc.
> Ich wünschte mir in den Anleitungen steht über jede Method und Klasse eine kleine Beschreibung.


Im Artikel findest Du einen Link auf http://modelmapper.org/getting-started/ - dort steht beschrieben, wie der ModelMapper funktioniert inkl. Benutzerhandbuch. 

Ansonsten besteht ja kein Zwang, diese Bibliothek - oder überhaupt eine - für das Mapping zu verwenden. Wir erzeugen z. T. direkt JsonObject-Instanzen, die wir zurückgeben oder haben DTO-Klassen, die wir manuell füllen bzw. als Adapter fungieren.


----------



## matze86 (24. Dez 2022)

mihe7 hat gesagt.:


> Ansonsten besteht ja kein Zwang, diese Bibliothek - oder überhaupt eine - für das Mapping zu verwenden. Wir erzeugen z. T. direkt JsonObject-Instanzen, die wir zurückgeben oder haben DTO-Klassen, die wir manuell füllen bzw. als Adapter fungieren.


Genau, das meine ich ja, ich habe aktuell kein grundsätzlichen Überblick wie so etwas generell funktionieren muss.
Aber ich werde mich nach und nach mal durcharbeiten, inkl. mit den hilfreichen Tipps hier im Forum.
Wenn ich mal noch eine Frage melde ich mich zu gegebener Zeit nochmal.


----------



## mihe7 (25. Dez 2022)

matze86 hat gesagt.:


> Genau, das meine ich ja, ich habe aktuell kein grundsätzlichen Überblick wie so etwas generell funktionieren muss.


Ganz grundsätzlich ist es einfach so, dass über die Leitung keine Objekte sondern eine Serialisierung der Objekte bzw. der Objektdaten gehen können. Damit Sender und Empfänger Daten austauschen können, müssen sie die "gleiche Sprache" sprechen. In Webservices wird oft JSON verwendet, weil es a) weit weniger geschwätzig als XML ist und b) von JavaScript im Browser sowieso verstanden wird. 

Jetzt hast Du also ein Person-Objekt und das muss irgendwie, sagen wir mal in JSON, serialisiert werden. SpringBoot/Jakarta EE können das automatisch: man gibt als Rückgabetyp z. B. Person an, liefert ein Person-Objekt zurück und das Framework erzeugt daraus einen JSON-Text. 

Statt nun direkt ein Person-Objekt zurückzuliefern, kann man auch eine "Sicht" auf eine Person (oder auf Person und Objekte weiterer Klassen) zurückliefern, dazu kann man ein DTO verwenden (s. dazu Kommentar #21 von @Oneixee5). 

Ein DTO ist einfach ein Objekt, das eben gerade die Daten enthält, die über die Leitung gehen sollen. Erstellt werden kann dieses wie jedes andere Objekt auch: man schreibt eine Klasse, erzeugt eine Instanz, setzt die Properties.

Nehmen wir mal an, wir hätten eine Person-Klasse, die Name, Vorname und Geburtsdatum darstellt. Aus Gründen des Datenschutzes sollen aber nur Name und Vorname über den REST-Endpoint geliefert werden. 

```
class PersonDTO {
    public String name;
    public String vorname;

    public PersonDTO(Perosn perosn) {
        name = person.getName();
        vorname = person.getVorname();
    }
}
```
Gibst Du jetzt in Deiner REST-Methode statt Person PersonDTO zurück, wird niemals das Geburtsdatum über die Leitung gehen. Die Person-Klasse kann später auch weitere Attribute erhalten, die die Außenwelt nichts angehen: das DTO stellt sicher, dass diese nicht übermittelt wreden.


----------



## matze86 (29. Dez 2022)

Ich habe mal das ganze im Ruhigen durchgearbeitet und versuch die Zusammenhänge zu verstehen.
Als erste nehme ich mal das Beispiel von https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application.

Das Prinzip ist, soweit ich es verstanden habe, ich habe wie in mein Post 17 und 20 eine normale User-Klasse, eine User-Repository-Klasse, eine Controller-Klasse.
Hinzu füge ich in folgendes: in der UserdtoApplication Klasse 

```
@Bean
public ModelMapper modelMapper() {
    return new ModelMapper();
}
```
 Warum auch immer das braucht.

Dann lege ich eine Klasse UserDTO , die z.b. nur die ID und den Namen frei gibt. Der Ort bleibt "geheim".

In Der Controller-Klasse lege ich diese Methode an

```
private userDTO convertToDto(User user) {
        userDTO userdto = modelMapper.map(user,UserDto.class);
        userDTO.setSubmissionDate(post.getSubmissionDate(),
            userService.getCurrentUser().getPreference().getTimezone());
        return userDTO;
```
Die "wandelt" den die User Klasse in UserDTO um.


```
@GetMapping(value = "/{id}")
    @ResponseBody
    public userDTO getPost(@PathVariable("id") Long id) {
        return convertToDto(userRepository.findById(id));
    }
```
In der Methode wird wird dann nur der Namen von User angezeigt, nicht mehr der Ort.
Ist das so in etwa richtig?

Was ich "noch" nicht verstanden habe ist, was hat es mit den ganzen "Service" unter https://github.com/eugenp/tutorials...in/java/com/baeldung/springpagination/service auf sich?


----------



## mihe7 (30. Dez 2022)

matze86 hat gesagt.:


> Warum auch immer das braucht.


Das Spring-Framework muss für die Injection einer ModelMapper-Instanz via `@Autowired` wissen, wie es eine Instanz von ModelMapper erzeugen kann. Das wird hier mit einer Factory-Method erledigt, die mit `@Bean` annotiert werden muss.



matze86 hat gesagt.:


> Ist das so in etwa richtig?


Ja, wobei ich das nur im Grundsatz sagen kann, weil ich den ModelMapper nicht kenne.



matze86 hat gesagt.:


> Was ich "noch" nicht verstanden habe ist, was hat es mit den ganzen "Service" unter https://github.com/eugenp/tutorials...in/java/com/baeldung/springpagination/service auf sich?


Die Annotation dient m. W. schlicht dazu, eine Spring-Komponente im Code explizit als Service (i. S. des Domain-Driven-Design) und nicht einfach als gewöhnliche Komponente darzustellen.


----------



## matze86 (30. Dez 2022)

OK. Also soweit habe ich es mal an meinen Code angepasst.
Also könnte ich die Services weg lassen und das in UserDTO einpflegen?

So sieht mein aktueller angepasster Code aus:

Der Controller

```
@Controller
@RequestMapping("/api")
public class ControllerUser{

    @Autowired
    private UserRepo userRepository;
    
    @Autowired
    private ModelMapper modelMapper;

    @GetMapping("/user/{id}")
    @ResponseBody
    public UserDTO getPost(@PathVariable Long id) {
        return convertToDto(userRepository.findById(id));
    }
   
     private UserDTO convertToDto(User user) {
         UserDTO userdto = modelMapper.map(user,UserDTO.class);
         return userdto;
     }
    
    
     private UserDTO convertToEntity(UserDTO userDTO) throws ParseException {
         UserDTO user = modelMapper.map(userDTO,UserDTO.class);
         return user;
     }
    
}
```
Da meckert Eclipse (Zeile 14), Die Methode convertToDto(User) im Typ ControllerUser ist für die Argumente nicht anwendbar (Optional<User>).

Die Methode convertToEntity muss ich auch noch vervollständigen, aber erst einmal muss es mit convertToDto funktionieren.

Der normale User:

```
@Entity
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String name;
    private String ort;

    public void setID(Long id) {
        this.id = id;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
  public void setOrt(String ort) {
      this.ort = ort;
  }
 
  public Long getID() {
      return this.id;
  }
 
  public String getName() {
      return this.name;
  }
 
  public String getOrt() {
      return this.ort;
  } 

}
```
Und der UserDTO

```
public class UserDTO {
    
    private String name;
    private Long id;
    
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setID(Long id) {
        this.id = id;
    }
    
     public Long getID() {
          return this.id;
      }
      
      public String getName() {
          return this.name;
      }
}
```

Irgend etwas fehlt in meinen Code noch, denn es gibt mir noch alles inkl. den Ort aus.


----------



## Oneixee5 (30. Dez 2022)

Dien Repository gibt offenbar ein Optional statt eines Entity zurück.

```
public class UserNotFoundException extends RuntimeException {

    public UserNotFoundException(String message) {
        super(message);
    }

}

...
   
    @GetMapping("/user/{id}")
    @ResponseBody
    public UserDTO getPost(@PathVariable Long id) {
        return convertToDto(userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Unavailable")));
    }
```


----------



## matze86 (3. Jan 2023)

Ich bin gerade dabei vom  UserDTO zum User einen Eintrag zu verändern.

Dabei legte ich die Methode "convertToEntity" an und die Methode die ein Name verändert.
Im Beispiel wurde gezeigt, dass man auch "UserDTO" mit als Parameter übergeben soll.
Jetzt stellt sich mir die Frage wie ich das zum testen in Postman eingeben soll und ob das so überhaupt funktioniert, denn ich möchte ja den Namen von UserDTO (der nur von außerhalb sichtbar ist) ändern, das User den Namen ändert.

Vielleicht kann mir jemand einen kleinen Tipp geben, ich habe vom vielen lesen leider den durchblick verloren.


```
//einen Eintrag verändern
@PutMapping("/put")
@ResponseBody
public UserDTO put(@RequestParam Long id, @RequestBody UserDTO userDto, @RequestParam String name) throws ParseException {
    User user = convertToEntity(userDto);
    user.setName(name);
    userRepository.save(user);
    return convertToDto(userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Unavailable")));
}

//von UserTDO zum User, hier uebergebe ich den modelMapper den UserDTO und soll ihn in User "umwandeln"
private User convertToEntity(UserDTO userDTO) throws ParseException {
    User user = modelMapper.map(userDTO,User.class);     
    return user;
}
```


----------



## matze86 (4. Jan 2023)

Das ganze habe ich jetzt nochmal auf komplett anderen Wege gemacht.
Es funktioniert auch und zeige es euch mal:
UserRepository

```
public interface UserRepo extends JpaRepository<User, Long>{
    List<User> findByName(String lastName);
    User findById(long id);
}
```
User

```
@Entity
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private String name;
    private String ort;

    public void setID(Long id) {
        this.id = id;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
  public void setOrt(String ort) {
      this.ort = ort;
  }
 
  public Long getID() {
      return this.id;
  }
 
  public String getName() {
      return this.name;
  }
 
  public String getOrt() {
      return this.ort;
  } 
}
```
UserDTO

```
public class UserDTO {
    
    private String name;
    private Long id;
    
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setID(Long id) {
        this.id = id;
    }
    
    public Long getID() {
          return this.id;
    }
      
    public String getName() {
          return this.name;
    }
}
```
UserConverter

```
@Component
public class UserConverter {

    
    public UserDTO entityToDTOo(User user) {
        ModelMapper mapper =new ModelMapper();
        UserDTO map = mapper.map(user, UserDTO.class);
        return map;
    }
    
    public List<UserDTO> entityToDTO(List<User> user) {
        return user.stream().map(x -> entityToDTOo(x)).collect(Collectors.toList());
    }
    
    public User dtoToEntity(UserDTO userdto) {
        ModelMapper mapper = new ModelMapper();
        User map = mapper.map(userdto, User.class);
        return map;
    }
    
    public List<User> dtoToEntity(List<UserDTO> userdto){
        return userdto.stream().map(x -> dtoToEntity(x)).collect(Collectors.toList());
    }   
}
```
und der Controller

```
@RestController
@RequestMapping("/api")
public class ControllerUser{

    @Autowired
    private UserRepo userRepository;
    
    @Autowired
    private UserConverter converter;

    //Alles ausgeben
    @GetMapping("/all")
    public List<UserDTO> findAll(){
        List<User> findAll = userRepository.findAll();
        return converter.entityToDTO(findAll);
    }
    
    //Ausgabe Objekt mit bestimmter ID
    @GetMapping("/user/{id}")
    public UserDTO findById(@PathVariable Long id) {
        User orElse = userRepository.findById(id).orElse(null);
        return converter.entityToDTOo(orElse);
    }
    
    //ein kompletes neues Objekt hinzufuegen
    @PostMapping("/neu")
    public UserDTO save(@RequestParam String name) {
        UserDTO dto = new UserDTO();
        dto.setName(name);
        User user = converter.dtoToEntity(dto);
        user =  userRepository.save(user);
        return converter.entityToDTOo(user);
    }
    
    //einen Eintrag verändern
    //und dien gesamten eintrag zurueck geben
    @PutMapping("/put")
    public UserDTO put(@RequestParam Long id, @RequestParam String name) {
        UserDTO dto = new UserDTO();
        dto.setName(name);
        dto.setID(id);
        User user = converter.dtoToEntity(dto);
        user =  userRepository.save(user);
        
        return converter.entityToDTOo(user);
    }
    
    //ein Eintrag löschen mit dem Parameter ID
    @DeleteMapping("/del")
    public List<UserDTO> loeschen(@RequestParam Long id) {
        userRepository.deleteById(id);
            
        return converter.entityToDTO(userRepository.findAll());
    }
    
    //hier wird explizit nach dem Namen gesuch und wiedergegeben
    @GetMapping("/einzelausgabe")
    public List<UserDTO> einzel(@RequestParam String name) {
        List<User> user = userRepository.findByName(name);
        return converter.entityToDTO(user);
    }             
}
```

Ist der Code so vertretbar?


----------



## mihe7 (4. Jan 2023)

matze86 hat gesagt.:


> Ist der Code so vertretbar?


Warum nicht?

Das einzige Problem, das ich hier sehe ist, dass das DTO ggf. den User überschreibt. Wir würden den User aus dem Repo holen und die Properties des DTO auf den persistenten User mappen.


----------



## matze86 (4. Jan 2023)

mihe7 hat gesagt.:


> Wir würden den User aus dem Repo holen und die Properties des DTO auf den persistenten User mappen.


Also im Prinzip umgekehrt?
Das die es nicht den User sonder den UserDTO in der Repo vertreten ist?


Zum Thema Sicherheit, Jetzt muss ich noch ein Username und auch Passwort vergeben.  Welche Methode ist hier so Zielführend und sicher?


----------



## mihe7 (4. Jan 2023)

matze86 hat gesagt.:


> Also im Prinzip umgekehrt?


Was heißt umgekehrt?



matze86 hat gesagt.:


> Das die es nicht den User sonder den UserDTO in der Repo vertreten ist?


Nein.

Es geht einfach darum, dass Du aus dem DTO direkt einen User erstellst. Diese Entity kann aber nur über die Informationen verfügen, die im DTO existieren, der Rest wäre "leer". Würdest Du nun das so erzeugte User-Objekt im Repo speichern, wären die ggf. im existierenden User bereits vorhandenen Informationen verloren.

Spendier der User-Entity einfach mal ein Geburtsdatum. Jetzt bekommst Du von außen eine Änderung via UserDTO, das neben der ID nur den Namen enthält. Du erzeugst nun ein neues User-Objekt mit ID und Namen und speicherst den Spaß im Repository ab. Damit überschreibst Du Dir das Geburtsdatum des bereits vorhandenen Users.

Deswegen machen wir etwas wie

```
User user = userRepository.findById(dto.getId());
user.setName(dto.getName()); // mappen der DTO-Properties auf den User
userRepository.save(user);
```


----------



## matze86 (4. Jan 2023)

OK. 
Und wie ist das mit Authorization? Kann man da OAuth2.0 nehmen?


----------



## KonradN (4. Jan 2023)

matze86 hat gesagt.:


> OK.
> Und wie ist das mit Authorization? Kann man da OAuth2.0 nehmen?


Das ist ja jetzt vom bisherigen Thema losgelöst. Generell ist das der Weg, den ich empfehlen würde. Also ein separates Identity Management (z.B. Keycloak - das ist einfach aufzusetzen auf Entwickler Systemen) und dann wird das lediglich genutzt. 

Damit umgehst Du viele kritische Dinge wie z.B, die sicherer Verwahrung von Daten. (Du hattest das speichern von Passwörtern erwähnt. Wenn, dann wird nur ein Hash - oder besser: "seeded hash" - gespeichert, aber niemals die Passwörter.) Etwas, das Du nicht speicherst, das kann nicht böswillig gelesen werden.

Und es bietet Firmen die Möglichkeit, da eigene identity Management Lösungen zu nutzen. (Kennt evtl. der eine oder andere: man will sich irgendwo anmelden wie z.B. Microsoft und nach Eingabe der Email Adresse erscheint dann ein Login des Firmen Systems)


----------



## matze86 (4. Jan 2023)

Alles klar vielen dank euch allen.


----------



## Oneixee5 (4. Jan 2023)

Ich denke ModelMapper könnte eine @Bean sein, dann kannst du ModelMapper in UserConverter injecten ohne neue Instanzen zu erzeugen.


----------



## matze86 (5. Jan 2023)

mihe7 hat gesagt.:


> Spendier der User-Entity einfach mal ein Geburtsdatum. Jetzt bekommst Du von außen eine Änderung via UserDTO, das neben der ID nur den Namen enthält. Du erzeugst nun ein neues User-Objekt mit ID und Namen und speicherst den Spaß im Repository ab. Damit überschreibst Du Dir das Geburtsdatum des bereits vorhandenen Users.



Aber was ich mich gerade frage, das geht nur bei Objekten die schon existieren. 

Das geht aber nicht wenn man ein neues Objekt erstellt, denn der DTO User hat ja nur "Rechte" auf name und id.
Da macht ja das erstellen keinen Sinn über DTO User. Oder wie ist das in der Prxis?


----------



## KonradN (5. Jan 2023)

matze86 hat gesagt.:


> Aber was ich mich gerade frage, das geht nur bei Objekten die schon existieren.


Das Aktualisieren eines vorhandenen Users macht nur Sinn, wenn der User existiert. Ja 



matze86 hat gesagt.:


> Das geht aber nicht wenn man ein neues Objekt erstellt, denn der DTO User hat ja nur "Rechte" auf name und id.
> Da macht ja das erstellen keinen Sinn über DTO User. Oder wie ist das in der Prxis?


Prinzipiell geht es genau so beim Erstellem von neuen Usern.

Aber die fachlichen Fragen kannst nur Du klären. Generell kann man mehrere DTO Klassen haben. Dann ahst Du halt noch eine UserCreateDTO Klasse, die nur Felder hat, die beim Erzeugen Sinn machen.


----------



## matze86 (5. Jan 2023)

Genau, die habe ich jetzt erstellt und funktioniert wie es funktionieren soll.

Bei der Put-Methode hatte ich einen Denkfehler, da wurde der ort z.b. immer gelöscht.
Jetzt sieht es so aus, und es funktioniert auch.
Vielen dank euch allen.


```
@PutMapping("/put")
    public UserDTO put(@RequestParam Long id, @RequestParam String name) {
        UserDTO dto = new UserDTO();
        dto.setID(id);
        dto.setName(name);
        User user = userRepository.findById(dto.getID()).orElse(null);
        user.setName(dto.getName());
        userRepository.save(user);
        return converter.entityToDTOo(user);
    }
```


----------



## KonradN (5. Jan 2023)

Also Dein Code ist so wenig Sinnvoll:

a) Warum erzeugst Du erst ein DTO, wenn Du es eh nicht brauchst? DTO sind Data Transfer Objects - also zur Weitergabe von Daten. Aber in Zeile 3 des Codes erzeugst Du eine Instanz, die Du nicht weiter gibst. Das ist so also schlicht sinnlos. In Zeile 6 kannst Du direkt die id verwenden und in Zeile 7 den Namen. Die DTO Klasse kommt also wirklich erst am Ende ins Spiel.

b) Was soll dieses orElse(null)? Damit kann user null sein und Du rennst in der folgenden Zeile in eine NPE. Und die NPE ist eine typische "EntwicklerIstZuBlödException" - das sollte dir bewusst sein!


----------



## mihe7 (5. Jan 2023)

Zu a) von @KonradN und weil ich das in #42 nicht gezeigt habe: wir hätten in dem Fall das DTO als Body des Put-Requests. Heißt, der Aufrufer übermittelt ein JSON in der Form

```
{
    "id": 4711,
    "name": "Daniel Düsentrieb"
}
```
Das wird dann automatisch in ein UserDTO konvertiert, das die Methode als Parameter erwartet. Bei ein, zwei Felder macht das aber nicht unbedingt Sinn.



KonradN hat gesagt.:


> Und die NPE ist eine typische "EntwicklerIstZuBlödException" - das sollte dir bewusst sein!


LOL. Man könnte die Abkürzung natürlich auch umdeuten: NPE = NotProfessionalException.


----------



## matze86 (5. Jan 2023)

Ok ich habe es geändert. Nur hat die Methode nicht wirklich Sinn.
Weil wenn ich bei den Argumenten noch den ort angebe, dann tut der ort ja auch überschrieben werden. 
Aber ich denke mal, das DTO ist meist nur für die Ausgabe gedacht, das der Anwender nicht alles sieht.

orElse() habe ich mit mit orElseThrow() verwechselt.


----------



## mihe7 (5. Jan 2023)

matze86 hat gesagt.:


> Weil wenn ich bei den Argumenten noch den ort angebe, dann tut der ort ja auch überschrieben werden.


Zeig mal, was Du da verbrochen hast, das gibt nämlich nicht wirklich Sinn.


----------



## KonradN (5. Jan 2023)

matze86 hat gesagt.:


> Weil wenn ich bei den Argumenten noch den ort angebe, dann tut der ort ja auch überschrieben werden.


Generell kann man sich das natürlich so überlegen, wie man das braucht.

Wenn es nur um ein Update geht, dann kann man ein DTO bauen, dass nur Referenzen enthält (Also bei Value Typen die entsprechende Wrapper Klasse). Dann kann man etwas nur dann aktualisieren, wenn es gesetzt wurde. Damit entfällt aber dann das Löschen von Werten - Aber statt null ist es ja denkbar, dass man den leeren String setzt oder so.

Also dann wäre da sowas wie:
`if (dto.getName() != null) entity.setName(dto.getName());`

Und auch ganz wichtig: Wenn Du ein REST Service haben willst, dann setzt Du da keine einzelnen Parameter sondern es wird ein DTO als Objekt übergeben - wie @mihe7 gesagt hat,


----------



## KonradN (5. Jan 2023)

Bezüglich dem JSON marshaling - da ist dieses Vorgehen relativ sauber, denn null Werte werden in der Regel einfach weggelassen. Wenn Du also nur id und name gesetzt hast, dann finden sich im JSON die anderen Werte nicht und man hat etwas wie

```
{
    id: 1234,
    name: "Some Name"
}
```


----------



## matze86 (5. Jan 2023)

Also mache ich es mit JSON, lasse die Parameter weg und übergebe nur das DTO Objekt.
Das ganze soll später von einen anderen Java-Programm abgerufen werden können.


----------



## KonradN (5. Jan 2023)

matze86 hat gesagt.:


> Also mache ich es mit JSON, lasse die Parameter weg und übergebe nur das DTO Objekt.
> Das ganze soll später von einen anderen Java-Programm abgerufen werden können.


Jein - Du selbst machst nichts mit JSON. Das passiert automatisch. Du hast einen Controller. In dem hast Du ein Mapping. Da baut also Spring Boot dann entsprechend alles für Dich auf. Dabei ist es Dir egal, wie die Daten ankommen. Spring Boot erlaubt JSON aber prinzipiell auch XML.

Das muss Dich als Entwickler nicht interessieren. Du erwartest einen Parameter und der ist vom Typ her dein DTO Objekt.


----------



## matze86 (5. Jan 2023)

Genau das meinte ich.  Mit JSON meinte ich damit beim Test über Postman, da kann man JSON wählen.

Macht sich das dann gut beim Anwenderprogramm mit Java, das ich über JSON arbeite?


----------



## KonradN (5. Jan 2023)

matze86 hat gesagt.:


> Genau das meinte ich.  Mit JSON meinte ich damit beim Test über Postman, da kann man JSON wählen.
> 
> Macht sich das dann gut beim Anwenderprogramm mit Java, das ich über JSON arbeite?


Ja, bei Postman arbeitest Du dann mit JSON.

Aber im Java Client wirst Du hoffentlich nicht direkt mit JSON arbeiten sondern auch mit den DTO Klassen. Die Libraries, die Spring Boot nutzt, kann auch ein Java Client nutzen. Dazu gibt es ja so Libraries wie RESTeasy und Co.


----------



## mihe7 (5. Jan 2023)

matze86 hat gesagt.:


> Mit JSON meinte ich damit beim Test über Postman, da kann man JSON wählen.


Ja.



matze86 hat gesagt.:


> Macht sich das dann gut beim Anwenderprogramm mit Java, das ich über JSON arbeite?


Wie meinst Du das? JSON ist ein Standardformat, das in REST-APIs gerne verwendet wird. In Java selbst arbeitest Du nicht mit JSON, sondern mit irgendwelchen Objekten.


----------



## matze86 (5. Jan 2023)

KonradN hat gesagt.:


> Aber im Java Client wirst Du hoffentlich nicht direkt mit JSON arbeiten sondern auch mit den DTO Klassen. Die Libraries, die Spring Boot nutzt, kann auch ein Java Client nutzen. Dazu gibt es ja so Libraries wie RESTeasy und Co.


Das wusste ich nicht, ich dachte man "direkt" drauf zugreifen und sich das Object zurückgeben lassen etc.

Also muss ich später beim Client auch spring Boot aufsetzen, mit ein DTO-Objekt der mit der entfernten Rest-API kommuniziert?


----------



## mihe7 (5. Jan 2023)

matze86 hat gesagt.:


> Also muss ich später beim Client auch spring Boot aufsetzen, mit ein DTO-Objekt der mit der entfernten Rest-API kommuniziert?


Nein, Du kannst Libs verwenden (z. B. RESTeasy), so wie das @KonradN ja auch geschrieben hat.


----------



## matze86 (Dienstag um 09:09)

mihe7 hat gesagt.:


> wir hätten in dem Fall das DTO als Body des Put-Requests. Heißt, der Aufrufer übermittelt ein JSON in der Form
> 
> ```
> {
> ...


Macht das mit auch bei PutMapping Sinn oder sollte man da die Variablen, die geändert werden sollten, als Parameter angeben?
Ich habe Name, Ort und Geburtsdatum und möchte aber nur den Ort ändern, da habe ich den Ort als Parameter übergeben.
Hoffe das ist so richtig.


----------



## KonradN (Dienstag um 09:34)

Also generell funktioniert es, oder? Also ist es kein klares falsch.

Aber ich selbst achte immer etwas auf die Methoden und was diese bedeuten. Und bei einer REST API kenne ich es in erster Linie so, dass Entities übergeben werden - an eine Ressource.

Du kannst also eine Entity mit id und Ort an die Ressource User geben um da dann etwas zu ändern. Dann ist nur die Frage: Welche Methode nimmt man da?

Da kann man z.B. schauen, was bei Mozilla dazu gesagt wird: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
Und da ist es eher kein PUT, da Du ja nichts ersetzt (oder neu erstellst). Da ist dann eher ein POST Request das Mittel der Wahl (Wenn ich entscheiden müsste).


----------



## matze86 (Dienstag um 12:21)

Das heißt also, ich übergebe (wie beim erstellen eines Objektes) eine UserDTO Entity, mit nur dem ort, die ID wird ja übergeben.
In der Methode erstelle ich ein User-Objekt, mit den ganzen Daten des Objektes mit der ID (Name, ort, geburtsdatum...).
Dann ersetze ich nur die Variablen die in der der UserDTO Entity mitgeteilt wurden (im dem Fall nur der ort), das andere bleibt.


----------



## Oneixee5 (Dienstag um 15:37)

matze86 hat gesagt.:


> Macht das mit auch bei PutMapping Sinn oder sollte man da die Variablen, die geändert werden sollten, als Parameter angeben?
> Ich habe Name, Ort und Geburtsdatum und möchte aber nur den Ort ändern, da habe ich den Ort als Parameter übergeben.
> Hoffe das ist so richtig.


Die Methode PUT dient zum Ändern eines Objektes. Es ist sinnvoll immer das ganze Objekt zu übergeben. So kann man in dem selben Endpunkt auch mehrere Dinge ändern und braucht keine separaten Endpunkte, z.B.: zum ändern des Namen und zum ändern des Ortes. Als Rückgabe des Endpunktes sollte wieder das gesamte neue Objekt übergeben werden. Im Client wird dann das bestehende Objekt durch die Rückgabe ersetzt.
Man muss dabei bedenken, Webanwendungen haben nicht nur einen Nutzer. Ein andere Nutzer könnte zwischenzeitlich den Vornamen geändert haben (sofern das nicht anderweitig ausgeschlossen wurde). Nachdem das gesamte Objekt zurückgegeben wurde kann auch der neue Vorname im Client angezeigt werden.
Die Datenmenge ist dabei zweitrangig und bei deinem DTO sowieso unbedeutend. Wenn man optimieren möchte könnte man die Objekte gezippt übertragen. Nur bei sehr großen Datenmengen würde ich anfangen die Objekte zu zerlegen.


----------



## KonradN (Dienstag um 16:14)

Oneixee5 hat gesagt.:


> Die Methode PUT dient zum Ändern eines Objektes.


Ach ja - der Moment, wenn einem klar wird, dass man etwas falsches geschrieben hat ... Meine Ausführungen in #64 waren bezüglich POST und PUT natürlich falsch - und ich habe mich da auf eine blöde Grundlage gestellt, die wenig optimal ist.

Daher nutze ich diesen Post als Chance, dies etwas zu korrigieren:

Also erstes die Frage: Wo kann man dies den gut beschrieben finden. Und da ist dann vermutlich die RFC mit am günstigsten:
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p2-semantics-16#section-4.3.3 

4.3.3 behandelt POST, 
4.3.4 dann PUT. Und dann wird schnell deutlich, dass ich in #64 irgendwie neben mir war 

In 4.3.4 findet sich dann auch ein Abschnitt, der den Unterschied deutlich beschreibt:


> The fundamental difference between the POST and PUT methods is
> highlighted by the different intent for the enclosed representation.
> The target resource in a POST request is intended to handle the
> enclosed representation according to the resource's own semantics,
> ...



Und das "the enclosed representation in a PUT request is defined as replacing the state of the target resource." beschfreibt ja auch genau das, was Du willst. Du hast eine target Resource (den User) und willst da einen state (den Ort) ändern.

Sorry, wenn ich da bei dem Beitrag eben Verwirrung gestiftet haben sollte.


----------

