eclipse-tractusx / managed-identity-wallet

Apache License 2.0
10 stars 23 forks source link

Refactoring swagger annotations in the Controllers #145

Closed mustafasalfiti closed 10 months ago

mustafasalfiti commented 11 months ago

just a little refactor to the controllers where we can easily at the end read the functionality of it, the refactor will remove all the annotations from controllers and pack them into a separate file where we can use decorations to keep the same functionality

An example:

Before (HoldersCredentialController)

/*
 * *******************************************************************************
 *  Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
 *
 *  See the NOTICE file(s) distributed with this work for additional
 *  information regarding copyright ownership.
 *
 *  This program and the accompanying materials are made available under the
 *  terms of the Apache License, Version 2.0 which is available at
 *  https://www.apache.org/licenses/LICENSE-2.0.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 *  License for the specific language governing permissions and limitations
 *  under the License.
 *
 *  SPDX-License-Identifier: Apache-2.0
 * ******************************************************************************
 */

package org.eclipse.tractusx.managedidentitywallets.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.managedidentitywallets.constant.RestURI;
import org.eclipse.tractusx.managedidentitywallets.service.HoldersCredentialService;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.List;
import java.util.Map;

/**
 * The type Holders credential controller.
 */
@RestController
@RequiredArgsConstructor
@Slf4j
@Tag(name = "Verifiable Credential - Holder")
public class HoldersCredentialController extends BaseController {

    private final HoldersCredentialService holdersCredentialService;

    /**
     * Gets credentials.
     *
     * @param credentialId     the credential id
     * @param issuerIdentifier the issuer identifier
     * @param type             the type
     * @param sortColumn       the sort column
     * @param sortTpe          the sort tpe
     * @param principal        the principal
     * @return the credentials
     */
    @ApiResponse(responseCode = "401", description = "The request could not be completed due to a failed authorization.", content = {@Content(examples = {})})
    @ApiResponse(responseCode = "403", description = "The request could not be completed due to a forbidden access", content = {@Content(examples = {})})
    @ApiResponse(responseCode = "500", description = "Any other internal server error", content = {@Content(examples = {
            @ExampleObject(name = "Internal server error", value = """
                    {
                      "type": "about:blank",
                      "title": "Error Title",
                      "status": 500,
                      "detail": "Error Details",
                      "instance": "API endpoint",
                      "properties": {
                        "timestamp": 1689762476720
                      }
                    }
                    """)
    })})
    @ApiResponse(responseCode = "404", description = "Wallet not found with caller BPN", content = {@Content(examples = {
            @ExampleObject(name = "Wallet not found with caller BPN", value = """
                    {
                        "type": "about:blank",
                        "title": "Wallet not found for identifier did:web:localhost:BPNL0000000",
                        "status": 404,
                        "detail": "Wallet not found for identifier did:web:localhost:BPNL0000000",
                        "instance": "/api/wallets/did%3Aweb%3Alocalhost%3ABPNL0000000/credentials",
                        "properties": {
                          "timestamp": 1689765541959
                        }
                      }
                    """)
    })})
    @ApiResponse(responseCode = "400", description = "The input does not comply to the syntax requirements", content = {
            @Content(examples = {
                    @ExampleObject(name = "Response in case of invalid data provided", value = """
                             {
                                 "type": "about:blank",
                                 "title": "title",
                                 "status": 400,
                                 "detail": "details",
                                 "instance": "API endpoint",
                                 "properties":
                                 {
                                     "timestamp": 1689760833962,
                                     "errors":
                                     {
                                     }
                                 }
                             }
                            """)
            })
    })
    @ApiResponse(responseCode = "200", description = "Credential list", content = {
            @Content(examples = {
                    @ExampleObject(name = "Credential list", value = """
                                                        {
                                                            "content":
                                                            [
                                                                {
                                                                    "@context":
                                                                    [
                                                                        "https://www.w3.org/2018/credentials/v1",
                                                                        "https://catenax-ng.github.io/product-core-schemas/SummaryVC.json",
                                                                        "https://w3id.org/security/suites/jws-2020/v1"
                                                                    ],
                                                                    "id": "did:web:localhost:BPNL000000000000#954d43de-ebed-481d-9e35-e3bbb311b8f5",
                                                                    "type":
                                                                    [
                                                                        "VerifiableCredential",
                                                                        "SummaryCredential"
                                                                    ],
                                                                    "issuer": "did:web:localhost:BPNL000000000000",
                                                                    "issuanceDate": "2023-07-14T11:05:48Z",
                                                                    "expirationDate": "2023-09-30T18:30:00Z",
                                                                    "credentialSubject":
                                                                    [
                                                                        {
                                                                            "contractTemplate": "https://public.catena-x.org/contracts/",
                                                                            "holderIdentifier": "BPNL000000000000",
                                                                            "id": "did:web:localhost:BPNL000000000000",
                                                                            "items":
                                                                            [
                                                                                "BpnCredential"
                                                                            ],
                                                                            "type": "SummaryCredential"
                                                                        }
                                                                    ],
                                                                    "proof":
                                                                    {
                                                                        "created": "2023-07-14T11:05:50Z",
                                                                        "jws": "eyJhbGciOiJFZERTQSJ9..4xwFUCtP0xXVEo5_lXd90Vv-TWO2FijZut-HZ5cozAQseexj8EpTkK1erhFbf2Ua1kb8pi_H5At5HiPkTxSIAQ",
                                                                        "proofPurpose": "proofPurpose",
                                                                        "type": "JsonWebSignature2020",
                                                                        "verificationMethod": "did:web:localhost:BPNL000000000000#"
                                                                    }
                                                                }
                                                            ],
                                                            "pageable":
                                                            {
                                                                "sort":
                                                                {
                                                                    "empty": false,
                                                                    "sorted": true,
                                                                    "unsorted": false
                                                                },
                                                                "offset": 0,
                                                                "pageNumber": 0,
                                                                "pageSize": 2147483647,
                                                                "paged": true,
                                                                "unpaged": false
                                                            },
                                                            "totalElements": 1,
                                                            "totalPages": 1,
                                                            "last": true,
                                                            "size": 2147483647,
                                                            "number": 0,
                                                            "sort":
                                                            {
                                                                "empty": false,
                                                                "sorted": true,
                                                                "unsorted": false
                                                            },
                                                            "first": true,
                                                            "numberOfElements": 1,
                                                            "empty": false
                                                        }
                            """)
            })
    })
    @Operation(description = "Permission: **view_wallets** OR **view_wallet** (The BPN of holderIdentifier must equal BPN of caller)\n\n Search verifiable credentials with filter criteria", summary = "Query Verifiable Credentials")
    @GetMapping(path = RestURI.CREDENTIALS, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<PageImpl<VerifiableCredential>> getCredentials(@Parameter(name = "credentialId", description = "Credential Id", examples = {@ExampleObject(name = "Credential Id", value = "did:web:localhost:BPNL000000000000#12528899-160a-48bd-ba15-f396c3959ae9")}) @RequestParam(required = false) String credentialId,
                                                                         @Parameter(name = "issuerIdentifier", description = "Issuer identifier(did of BPN)", examples = {@ExampleObject(name = "bpn", value = "BPNL000000000000", description = "bpn"), @ExampleObject(description = "did", name = "did", value = "did:web:localhost:BPNL000000000000")}) @RequestParam(required = false) String issuerIdentifier,
                                                                         @Parameter(name = "type", description = "Type of VC", examples = {@ExampleObject(name = "SummaryCredential", value = "SummaryCredential", description = "SummaryCredential"), @ExampleObject(description = "BpnCredential", name = "BpnCredential", value = "BpnCredential")}) @RequestParam(required = false) List<String> type,
                                                                         @Parameter(name = "sortColumn", description = "Sort column name",
                                                                                 examples = {
                                                                                         @ExampleObject(value = "createdAt", name = "creation date"),
                                                                                         @ExampleObject(value = "issuerDid", name = "Issuer did"),
                                                                                         @ExampleObject(value = "type", name = "Credential type"),
                                                                                         @ExampleObject(value = "credentialId", name = "Credential id"),
                                                                                         @ExampleObject(value = "selfIssued", name = "Self issued credential"),
                                                                                         @ExampleObject(value = "stored", name = "Stored credential")
                                                                                 }
                                                                         ) @RequestParam(required = false, defaultValue = "createdAt") String sortColumn,
                                                                         @Parameter(name = "sortTpe", description = "Sort order", examples = {@ExampleObject(value = "desc", name = "Descending order"), @ExampleObject(value = "asc", name = "Ascending order")}) @RequestParam(required = false, defaultValue = "desc") String sortTpe,
                                                                         @Min(0) @Max(Integer.MAX_VALUE) @Parameter(description = "Page number, Page number start with zero") @RequestParam(required = false, defaultValue = "0") int pageNumber,
                                                                         @Min(0) @Max(Integer.MAX_VALUE) @Parameter(description = "Number of records per page") @RequestParam(required = false, defaultValue = Integer.MAX_VALUE + "") int size,
                                                                         Principal principal) {
        log.debug("Received request to get credentials. BPN: {}", getBPNFromToken(principal));
        return ResponseEntity.status(HttpStatus.OK).body(holdersCredentialService.getCredentials(credentialId, issuerIdentifier, type, sortColumn, sortTpe, pageNumber, size, getBPNFromToken(principal)));
    }

    /**
     * Issue credential response entity.
     *
     * @param data      the data
     * @param principal the principal
     * @return the response entity
     */
    @ApiResponse(responseCode = "201", description = "Success Response", content = {@Content(examples = {
            @ExampleObject(name = "Success Response", value = """
                                        {
                                            "@context":
                                            [
                                                "https://www.w3.org/2018/credentials/v1",
                                                "https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json",
                                                "https://w3id.org/security/suites/jws-2020/v1"
                                            ],
                                            "id": "did:web:localhost:BPNL000000000000#319a2641-9407-4c39-bf51-a4a109b59604",
                                            "type":
                                            [
                                                "VerifiableCredential",
                                                "BankDetails"
                                            ],
                                            "issuer": "did:web:localhost:BPNL000000000000",
                                            "issuanceDate": "2023-07-19T13:41:52Z",
                                            "expirationDate": "2024-12-31T18:30:00Z",
                                            "credentialSubject":
                                            [
                                                {
                                                    "bpn": "BPNL000000000000",
                                                    "bankName": "Dummy Bank",
                                                    "id": "did:web:localhost:BPNL000000000000",
                                                    "type": "BankDetails",
                                                    "accountNumber": "123456789"
                                                }
                                            ],
                                            "proof":
                                            {
                                                "proofPurpose": "proofPurpose",
                                                "verificationMethod": "did:web:localhost:BPNL000000000000#",
                                                "type": "JsonWebSignature2020",
                                                "created": "2023-07-19T13:41:54Z",
                                                "jws": "eyJhbGciOiJFZERTQSJ9..fdqaAsPhQ5xZhQiRvWliDVXX-R9NzCvFXGUAOyQ8yE1hmf_4cvxS7JFuEojjsi3V-n66iiRCUFEXsnv56XPgDA"
                                            }
                                        }
                    """)
    })})
    @ApiResponse(responseCode = "404", description = "Wallet not found with caller BPN", content = {@Content(examples = {
            @ExampleObject(name = "Wallet not found with caller BPN", value = """
                    {
                       "type": "about:blank",
                       "title": "Wallet not found for identifier did:web:localhost:BPNL0000000501",
                       "status": 404,
                       "detail": "Wallet not found for identifier did:web:localhost:BPNL0000000501",
                       "instance": "/api/wallets/did%3Aweb%3Alocalhost%3ABPNL0000000501",
                       "properties": {
                         "timestamp": 1689764377224
                       }
                     }
                    """)
    })})
    @ApiResponse(responseCode = "401", description = "The request could not be completed due to a failed authorization.", content = {@Content(examples = {})})
    @ApiResponse(responseCode = "403", description = "The request could not be completed due to a forbidden access", content = {@Content(examples = {})})
    @ApiResponse(responseCode = "500", description = "Any other internal server error", content = {@Content(examples = {
            @ExampleObject(name = "Internal server error", value = """
                    {
                      "type": "about:blank",
                      "title": "Error Title",
                      "status": 500,
                      "detail": "Error Details",
                      "instance": "API endpoint",
                      "properties": {
                        "timestamp": 1689762476720
                      }
                    }
                    """)
    })})
    @ApiResponse(responseCode = "400", description = "The input does not comply to the syntax requirements", content = {
            @Content(examples = {
                    @ExampleObject(name = "Response in case of invalid data provided", value = """
                             {
                                 "type": "about:blank",
                                 "title": "Invalid data provided",
                                 "status": 400,
                                 "detail": "details",
                                 "instance": "API endpoint",
                                 "properties":
                                 {
                                     "timestamp": 1689760833962,
                                     "errors":
                                     {
                                         "filed": "filed error message"
                                     }
                                 }
                             }
                            """)
            })
    })
    @Operation(summary = "Issue Verifiable Credential", description = "Permission: **update_wallets** OR **update_wallet** (The BPN of the issuer of the Verifiable Credential must equal BPN of caller)\nIssue a verifiable credential with a given issuer DID")
    @PostMapping(path = RestURI.CREDENTIALS, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @io.swagger.v3.oas.annotations.parameters.RequestBody(content = {
            @Content(examples = @ExampleObject("""
                                {
                                  "@context": [
                                    "https://www.w3.org/2018/credentials/v1",
                                    "https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json",
                                    "https://w3id.org/security/suites/jws-2020/v1"
                                  ],
                                  "id": "did:web:localhost:BPNL000000000000#f73e3631-ba87-4a03-bea3-b28700056879",
                                  "type": [
                                    "VerifiableCredential",
                                    "BankDetails"
                                  ],
                                  "issuer": "did:web:localhost:BPNL000000000000",
                                  "expirationDate": "2024-12-31T18:30:00Z",
                                  "issuanceDate": "2023-07-19T09:11:34Z",
                                  "credentialSubject": [
                                    {
                                      "bpn": "BPNL000000000000",
                                      "id": "did:web:localhost:BPNL000000000000",
                                      "type": "BankDetails",
                                      "accountNumber": "123456789",
                                      "bankName":"Dummy Bank"
                                    }
                                  ]
                                }
                    """))
    })
    public ResponseEntity<VerifiableCredential> issueCredential(@RequestBody Map<String, Object> data, Principal principal) {
        log.debug("Received request to issue credential. BPN: {}", getBPNFromToken(principal));
        return ResponseEntity.status(HttpStatus.CREATED).body(holdersCredentialService.issueCredential(data, getBPNFromToken(principal)));
    }
}

After (HoldersCredentialController)

/*
 * *******************************************************************************
 *  Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
 *
 *  See the NOTICE file(s) distributed with this work for additional
 *  information regarding copyright ownership.
 *
 *  This program and the accompanying materials are made available under the
 *  terms of the Apache License, Version 2.0 which is available at
 *  https://www.apache.org/licenses/LICENSE-2.0.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 *  License for the specific language governing permissions and limitations
 *  under the License.
 *
 *  SPDX-License-Identifier: Apache-2.0
 * ******************************************************************************
 */

package org.eclipse.tractusx.managedidentitywallets.controller;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.managedidentitywallets.apidocs.HoldersCredentialControllerApiDocs.GetCredentialsApiDocs;
import org.eclipse.tractusx.managedidentitywallets.apidocs.HoldersCredentialControllerApiDocs.IssueCredentialApiDoc;
import org.eclipse.tractusx.managedidentitywallets.constant.RestURI;
import org.eclipse.tractusx.managedidentitywallets.service.HoldersCredentialService;
import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;

import java.security.Principal;
import java.util.List;
import java.util.Map;

/**
 * The type Holders credential controller.
 */
@RestController
@RequiredArgsConstructor
@Slf4j
@Tag(name = "Verifiable Credential - Holder")
public class HoldersCredentialController extends BaseController {

    private final HoldersCredentialService holdersCredentialService;

    /**
     * Gets credentials.
     *
     * @param credentialId     the credential id
     * @param issuerIdentifier the issuer identifier
     * @param type             the type
     * @param sortColumn       the sort column
     * @param sortTpe          the sort tpe
     * @param principal        the principal
     * @return the credentials
    */
    @GetCredentialsApiDocs
    @GetMapping(path = RestURI.CREDENTIALS, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<PageImpl<VerifiableCredential>> getCredentials(@Parameter(name = "credentialId", description = "Credential Id", examples = {@ExampleObject(name = "Credential Id", value = "did:web:localhost:BPNL000000000000#12528899-160a-48bd-ba15-f396c3959ae9")}) @RequestParam(required = false) String credentialId,
                                                                         @Parameter(name = "issuerIdentifier", description = "Issuer identifier(did of BPN)", examples = {@ExampleObject(name = "bpn", value = "BPNL000000000000", description = "bpn"), @ExampleObject(description = "did", name = "did", value = "did:web:localhost:BPNL000000000000")}) @RequestParam(required = false) String issuerIdentifier,
                                                                         @Parameter(name = "type", description = "Type of VC", examples = {@ExampleObject(name = "SummaryCredential", value = "SummaryCredential", description = "SummaryCredential"), @ExampleObject(description = "BpnCredential", name = "BpnCredential", value = "BpnCredential")}) @RequestParam(required = false) List<String> type,
                                                                         @Parameter(name = "sortColumn", description = "Sort column name",
                                                                                 examples = {
                                                                                         @ExampleObject(value = "createdAt", name = "creation date"),
                                                                                         @ExampleObject(value = "issuerDid", name = "Issuer did"),
                                                                                         @ExampleObject(value = "type", name = "Credential type"),
                                                                                         @ExampleObject(value = "credentialId", name = "Credential id"),
                                                                                         @ExampleObject(value = "selfIssued", name = "Self issued credential"),
                                                                                         @ExampleObject(value = "stored", name = "Stored credential")
                                                                                 }
                                                                         ) @RequestParam(required = false, defaultValue = "createdAt") String sortColumn,
                                                                         @Parameter(name = "sortTpe", description = "Sort order", examples = {@ExampleObject(value = "desc", name = "Descending order"), @ExampleObject(value = "asc", name = "Ascending order")}) @RequestParam(required = false, defaultValue = "desc") String sortTpe,
                                                                         @Min(0) @Max(Integer.MAX_VALUE) @Parameter(description = "Page number, Page number start with zero") @RequestParam(required = false, defaultValue = "0") int pageNumber,
                                                                         @Min(0) @Max(Integer.MAX_VALUE) @Parameter(description = "Number of records per page") @RequestParam(required = false, defaultValue = Integer.MAX_VALUE + "") int size,
                                                                         Principal principal) {
        log.debug("Received request to get credentials. BPN: {}", getBPNFromToken(principal));
        return ResponseEntity.status(HttpStatus.OK).body(holdersCredentialService.getCredentials(credentialId, issuerIdentifier, type, sortColumn, sortTpe, pageNumber, size, getBPNFromToken(principal)));
    }

    /**
     * Issue credential response entity.
     *
     * @param data      the data
     * @param principal the principal
     * @return the response entity
     */

    @IssueCredentialApiDoc
    @PostMapping(path = RestURI.CREDENTIALS, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<VerifiableCredential> issueCredential(@RequestBody Map<String, Object> data, Principal principal) {
        log.debug("Received request to issue credential. BPN: {}", getBPNFromToken(principal));
        return ResponseEntity.status(HttpStatus.CREATED).body(holdersCredentialService.issueCredential(data, getBPNFromToken(principal)));
    }
}

The parameters will also be seperated and refactored.

m-gora commented 11 months ago

please look at discussion #192 .