From 674c7f734e5e7547ac61109d6bd23b5c253176de Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 15:07:20 +0100 Subject: [PATCH 1/5] chore(project): add CI workflow, license, makefile, docs, and examples --- .convcommit | 76 ++++++++++++++++++++++++++ .github/assets/repo-header-a3.png | Bin 0 -> 84779 bytes .github/workflows/go.yml | 26 +++++++++ .gitignore | 4 ++ LICENSE | 21 ++++++++ Makefile | 63 ++++++++++++++++++++++ README.md | 86 +++++++++++++++++++++++++++--- docs/code-of-conduct.md | 30 +++++++++++ docs/contributing.md | 45 ++++++++++++++++ examples/api_calls.go | 29 ++++++++++ examples/token_generation.go | 34 ++++++++++++ 11 files changed, 407 insertions(+), 7 deletions(-) create mode 100644 .convcommit create mode 100644 .github/assets/repo-header-a3.png create mode 100644 .github/workflows/go.yml create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 docs/code-of-conduct.md create mode 100644 docs/contributing.md create mode 100644 examples/api_calls.go create mode 100644 examples/token_generation.go diff --git a/.convcommit b/.convcommit new file mode 100644 index 0000000..0eed165 --- /dev/null +++ b/.convcommit @@ -0,0 +1,76 @@ +# convcommit - Conventional Commit message builder +# This file is read by the `convcommit` CLI tool to populate +# the interactive selector menus. +# Commit this file to share the project's commit vocabulary with the team. +# +# FORMAT +# type: — commit type option (e.g. fix, feat, docs) +# scope: — commit scope option +# message: — commit message template +# +# SPECIAL PREFIXES +# ~ — marks the default selection +# _ — enables free-text manual input (press ".") +# [X] — forces key letter X for this entry (e.g. [B]build, [W]wip) +# +# HOW TO USE (interactive) +# Run `convcommit` in a git repo. A menu appears for type, scope, message. +# Press the letter in brackets [A][B]... or [.] for free-text input. +# Stage and push in one shot: +# convcommit -a -p +# +# HOW TO USE (direct flags — scripts, AI agents) +# Bypass the selector entirely with explicit flags: +# convcommit --type fix --scope auth --message "fix null pointer" --push +# convcommit -t feat -s api -m "add endpoint" -a -p +# +# SMART PATTERN — stage specific files and commit in one command +# Use --add instead of nested command substitution. +# Anti-pattern (avoid): +# msg=$(convcommit --type fix --message "fix") && git commit -m "$msg" && git push +# Recommended: +# convcommit --add src/auth.sh --type fix --scope auth --message "fix null pointer" --push +# Stage multiple files: +# convcommit --add src/auth.sh --add tests/auth_test.sh -t test -s auth -m "add tests" -p +# +# HOW TO USE (pipe / non-interactive) +# Pipe selections as lines: one per stage (type, scope, message). +# Use the letter shown in the menu, or "." to trigger free-text input. +# Examples: +# printf "G\n.\nfix null pointer in login\n" | convcommit +# printf "F\n\nadd endpoint\n" | convcommit -a -p +# Capture just the formatted message: +# msg=$(printf "G\n\nfix null pointer\n" | convcommit) +# +# OTHER USEFUL FLAGS +# --reset Regenerate this file with the latest defaults +# --help Show all options +# +# INSTALLATION +# convcommit is a single bash file with no dependencies. +# Install it locally in your project: +# curl -fsSL https://raw.githubusercontent.com/francescobianco/convcommit/refs/heads/main/bin/convcommit \ +# -o bin/convcommit && chmod +x bin/convcommit +# Or system-wide: +# curl -fsSL https://raw.githubusercontent.com/francescobianco/convcommit/refs/heads/main/bin/convcommit \ +# -o /usr/local/bin/convcommit && chmod +x /usr/local/bin/convcommit +type:[B]build +type:~chore +type:[D]docs +type:deps +type:feat +type:fix +type:ci +type:init +type:merge +type:perf +type:refactor +type:revert +type:security +type:style +type:test +type:[W]wip +scope:_ +scope:~ +message:_ +message:~_ diff --git a/.github/assets/repo-header-a3.png b/.github/assets/repo-header-a3.png new file mode 100644 index 0000000000000000000000000000000000000000..c50835397f1546dd581e60c9c14bbf55ec0a379f GIT binary patch literal 84779 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 bWo>Y5VRU6ZDU)G400000NkvXXu0mjfFszB7 literal 0 HcmV?d00001 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..ad1363d --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,26 @@ + +name: build + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... diff --git a/.gitignore b/.gitignore index d8b3388..d6bb5b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# IDEs and editors +.idea/ +.vscode/ + # If you prefer the allow list template instead of the deny list, see community template: # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9f074c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Openapi® + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a35e742 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +#!make + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # +# ____ _ # +# / __ \____ ___ ____ ____ _____ (_) ® # +# / / / / __ \/ _ \/ __ \/ __ `/ __ \/ / # +# / /_/ / /_/ / __/ / / / /_/ / /_/ / / # +# \____/ .___/\___/_/ /_/\__,_/ .___/_/ # +# /_/ /_/ # +# # +# The Largest Certified API Marketplace # +# Accelerate Digital Transformation • Simplify Processes • Lead Industry # +# # +# ═══════════════════════════════════════════════════════════════════════ # +# # +# Project: openapi-rust-sdk # +# Version: 0.1.0 # +# Author: Michael Cuffaro (@maiku1008) # +# Copyright: (c) 2025 Openapi®. All rights reserved. # +# License: MIT # +# Maintainer: Francesco Bianco # +# Contact: https://openapi.com/ # +# Repository: https://github.com/openapi/openapi-php-sdk/ # +# Documentation: https://console.openapi.com/ # +# # +# ═══════════════════════════════════════════════════════════════════════ # +# # +# "Truth lies at the source of the stream." # +# — English Proverb # +# # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +## ========= +## Variables +## ========= + +VERSION := 1.2.1 + +## ==================== +## Development Commands +## ==================== + +dev-push: + @git config credential.helper 'cache --timeout=3600' + @git add . + @git commit -m "$$(read -p 'Commit message: ' msg; echo $$msg)" || true + @git push + +## ================ +## Release Commands +## ================ + +push: + @git add . + @git commit -am "Updated at $$(date)" || true + @git push + +release: push + @git add . + @git commit -m "Update PHP SDK to version ${VERSION}" || echo "No changes to commit" + @git tag -fa "${VERSION}" -m "${VERSION}" + @git push origin --tags -f \ No newline at end of file diff --git a/README.md b/README.md index 5aa74df..30e6889 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,47 @@ +
+ + Openapi SDK for PHP + + +

Openapi® client for PHP

+

The perfect starting point to integrate Openapi® within your PHP project

+ +[![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) +[![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) +[![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +
+[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members) +
+ +## Overview + +A minimal and agnostic PHP SDK for Openapi, inspired by a clean client implementation. This SDK provides only the core HTTP primitives needed to interact with any Openapi service. + +## Pre-requisites + +Before using the Openapi PHP Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment + +## Features + +- **Agnostic Design**: No API-specific classes, works with any OpenAPI service +- **Minimal Dependencies**: Only requires PHP 8.0+ and cURL +- **OAuth Support**: Built-in OAuth client for token management +- **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods +- **Clean Interface**: Similar to the Rust SDK design + +## What you can do + +With the Openapi PHP Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: + +- 📩 **Send SMS messages** with delivery reports and custom sender IDs +- 💸 **Process bills and payments** in real time via API +- 🧾 **Send electronic invoices** securely to the Italian Revenue Agency +- 📄 **Generate PDFs** from HTML content, including JavaScript rendering +- ✉️ **Manage certified emails** and legal communications via Italian Legalmail + +For a complete list of all available services, check out the [Openapi Marketplace](https://console.openapi.com/) 🌐 # OpenApi IT Go Client @@ -104,21 +148,49 @@ func main() { } ``` + ## Contributing -Contributions are always welcome! +Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. + +See [docs/contributing.md](docs/contributing.md) for detailed instructions on how to get started. Please make sure to follow this project's [docs/code-of-conduct.md](docs/code-of-conduct.md) to help maintain a welcoming and collaborative environment. + +## Authors + +Meet the project authors: -See `contributing.md` for ways to get started. +- L. Paderi ([@lpaderiAltravia](https://www.github.com/lpaderiAltravia)) +- Openapi Team ([@openapi-it](https://github.com/openapi-it)) -Please adhere to this project's `code of conduct`. +## Partners +Meet our partners using Openapi or contributing to this SDK: + +- [Blank](https://www.blank.app/) +- [Credit Safe](https://www.creditsafe.com/) +- [Deliveroo](https://deliveroo.it/) +- [Gruppo MOL](https://molgroupitaly.it/it/) +- [Jakala](https://www.jakala.com/) +- [Octotelematics](https://www.octotelematics.com/) +- [OTOQI](https://otoqi.com/) +- [PWC](https://www.pwc.com/) +- [QOMODO S.R.L.](https://www.qomodo.me/) +- [SOUNDREEF S.P.A.](https://www.soundreef.com/) + +## Our Commitments + +We believe in open source and we act on that belief. We became Silver Members +of the Linux Foundation because we wanted to formally support the ecosystem +we build on every day. Open standards, open collaboration, and open governance +are part of how we work and how we think about software. ## License -[MIT](https://choosealicense.com/licenses/mit/) +This project is licensed under the [MIT License](LICENSE). +The MIT License is a permissive open-source license that allows you to freely use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided that the original copyright notice and this permission notice are included in all copies or substantial portions of the software. -## Authors +In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. + +For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). -- [@maiku1008](https://www.github.com/maiku1008) -- [@openapi-it](https://github.com/openapi-it) diff --git a/docs/code-of-conduct.md b/docs/code-of-conduct.md new file mode 100644 index 0000000..4e71723 --- /dev/null +++ b/docs/code-of-conduct.md @@ -0,0 +1,30 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project a harassment-free experience for everyone. + +## Our Standards + +Examples of positive behavior: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy toward other community members + +Examples of unacceptable behavior: + +- Harassment, intimidation, or discrimination +- Public or private insults and derogatory comments +- Publishing others’ private information without consent +- Any other conduct reasonably considered inappropriate + +## Enforcement + +Instances of unacceptable behavior may be reported by contacting the project team at ``. All complaints will be reviewed promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1. \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..d3abc7b --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,45 @@ +# Contributing to Openapi SDK + +Thanks for considering contributing! 🎉 +We welcome all kinds of contributions: bug reports, feature requests, documentation improvements, and code enhancements. + +## How to Contribute + +1. **Fork the repository** and clone it locally: + ```bash + git clone https://github.com//.git + ``` + +2. **Create a branch** for your feature or fix: + ```bash + git checkout -b feature/your-feature-name + ``` + +3. **Make your changes** and commit them: + ```bash + git commit -m "Add some feature" + ``` + +4. **Push your branch** to your fork: + ```bash + git push origin feature/your-feature-name + ``` + +5. **Open a Pull Request** describing your changes. + +## Guidelines + +* Follow the existing **Php coding style**. +* Include **tests** for new features or bug fixes when applicable. +* Keep **commit messages clear and concise**. +* Update **documentation** as needed for your changes. + +## Reporting Issues + +To report bugs or request features, please **open an issue** on GitHub including: + +* Clear description of the problem or feature. +* Steps to reproduce (if applicable). +* Relevant logs or screenshots. + +Thank you for helping improve Openapi SDK! 🚀 \ No newline at end of file diff --git a/examples/api_calls.go b/examples/api_calls.go new file mode 100644 index 0000000..75d7401 --- /dev/null +++ b/examples/api_calls.go @@ -0,0 +1,29 @@ +', '', true); + + $scopes = [ + 'GET:test.imprese.openapi.it/advance', + 'POST:test.postontarget.com/fields/country' + ]; + + $ttl = 3600; + $result = $oauthClient->createToken($scopes, $ttl); + + $tokenData = json_decode($result, true); + + if (isset($tokenData['token'])) { + echo "Generated token: " . $tokenData['token'] . PHP_EOL; + echo "Token created successfully!" . PHP_EOL; + } else { + echo "Error creating token: " . $result . PHP_EOL; + } + +} catch (Exception $e) { + echo "Error: " . $e->getMessage() . PHP_EOL; +} \ No newline at end of file diff --git a/examples/token_generation.go b/examples/token_generation.go new file mode 100644 index 0000000..89a4a39 --- /dev/null +++ b/examples/token_generation.go @@ -0,0 +1,34 @@ +'; + $client = new Client($token); + + // GET request with parameters + $params = [ + 'denominazione' => 'altravia', + 'provincia' => 'RM', + 'codice_ateco' => '6201' + ]; + + $result = $client->get('https://test.imprese.openapi.it/advance', $params); + echo "GET API Response: " . $result . PHP_EOL; + + // POST request with payload + $payload = [ + 'limit' => 10, + 'query' => [ + 'country_code' => 'IT' + ] + ]; + + $result = $client->post('https://test.postontarget.com/fields/country', $payload); + echo "POST API Response: " . $result . PHP_EOL; + +} catch (Exception $e) { + echo "Error: " . $e->getMessage() . PHP_EOL; +} \ No newline at end of file From 250052211b7fe64869f8a781e9e2224d170f42ab Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 15:15:15 +0100 Subject: [PATCH 2/5] fix(examples): convert PHP examples to Go and reorganize into subdirectories --- Makefile | 11 +- README.md | 91 ++++------ examples/api_calls.go | 29 --- examples/api_calls/api_calls.go | 51 ++++++ examples/token_generation.go | 34 ---- examples/token_generation/token_generation.go | 39 ++++ pkg/client/client_test.go | 55 ++++++ pkg/client/oauthclient_test.go | 170 ++++++++++++++++++ 8 files changed, 357 insertions(+), 123 deletions(-) delete mode 100644 examples/api_calls.go create mode 100644 examples/api_calls/api_calls.go delete mode 100644 examples/token_generation.go create mode 100644 examples/token_generation/token_generation.go create mode 100644 pkg/client/client_test.go create mode 100644 pkg/client/oauthclient_test.go diff --git a/Makefile b/Makefile index a35e742..3487268 100644 --- a/Makefile +++ b/Makefile @@ -14,14 +14,14 @@ # # # ═══════════════════════════════════════════════════════════════════════ # # # -# Project: openapi-rust-sdk # +# Project: openapi-go-sdk # # Version: 0.1.0 # -# Author: Michael Cuffaro (@maiku1008) # +# Author: L. Paderi (@lpaderiAltravia) # # Copyright: (c) 2025 Openapi®. All rights reserved. # # License: MIT # # Maintainer: Francesco Bianco # # Contact: https://openapi.com/ # -# Repository: https://github.com/openapi/openapi-php-sdk/ # +# Repository: https://github.com/openapi/openapi-go-sdk/ # # Documentation: https://console.openapi.com/ # # # # ═══════════════════════════════════════════════════════════════════════ # @@ -41,6 +41,9 @@ VERSION := 1.2.1 ## Development Commands ## ==================== +test: + @go test ./... + dev-push: @git config credential.helper 'cache --timeout=3600' @git add . @@ -58,6 +61,6 @@ push: release: push @git add . - @git commit -m "Update PHP SDK to version ${VERSION}" || echo "No changes to commit" + @git commit -m "Update Go SDK to version ${VERSION}" || echo "No changes to commit" @git tag -fa "${VERSION}" -m "${VERSION}" @git push origin --tags -f \ No newline at end of file diff --git a/README.md b/README.md index 30e6889..cb65c43 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,38 @@
- Openapi SDK for PHP + Openapi SDK for Go -

Openapi® client for PHP

-

The perfect starting point to integrate Openapi® within your PHP project

+

Openapi® client for Go

+

The perfect starting point to integrate Openapi® within your Go project

-[![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) -[![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) -[![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) -[![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) -[![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![Build Status](https://github.com/openapi/openapi-go-sdk/actions/workflows/go.yml/badge.svg)](https://github.com/openapi/openapi-go-sdk/actions/workflows/go.yml) +[![Go Report Card](https://goreportcard.com/badge/github.com/openapi-it/openapi-cli-go)](https://goreportcard.com/report/github.com/openapi-it/openapi-cli-go) +[![Go Reference](https://pkg.go.dev/badge/github.com/openapi-it/openapi-cli-go.svg)](https://pkg.go.dev/github.com/openapi-it/openapi-cli-go) +[![License](https://img.shields.io/github/license/openapi/openapi-go-sdk)](LICENSE)
[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members)
## Overview -A minimal and agnostic PHP SDK for Openapi, inspired by a clean client implementation. This SDK provides only the core HTTP primitives needed to interact with any Openapi service. +A minimal and agnostic Go SDK for Openapi, providing only the core HTTP primitives needed to interact with any Openapi service. ## Pre-requisites -Before using the Openapi PHP Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment +Before using the Openapi Go Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment. ## Features -- **Agnostic Design**: No API-specific classes, works with any OpenAPI service -- **Minimal Dependencies**: Only requires PHP 8.0+ and cURL +- **Agnostic Design**: No API-specific classes, works with any Openapi service +- **Minimal Dependencies**: Only requires Go 1.19+ - **OAuth Support**: Built-in OAuth client for token management -- **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods -- **Clean Interface**: Similar to the Rust SDK design +- **HTTP Primitives**: GET, POST, PUT, DELETE and other HTTP methods +- **Clean Interface**: Simple and idiomatic Go API ## What you can do -With the Openapi PHP Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: +With the Openapi Go Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: - 📩 **Send SMS messages** with delivery reports and custom sender IDs - 💸 **Process bills and payments** in real time via API @@ -43,83 +42,72 @@ With the Openapi PHP Client, you can easily interact with a variety of services For a complete list of all available services, check out the [Openapi Marketplace](https://console.openapi.com/) 🌐 -# OpenApi IT Go Client - -This client is used to interact with the API found at [openapi.it](https://openapi.it/) - -## Pre-requisites - -Before using the OpenApi IT Go Client, you will need an account at [openapi.it](https://openapi.it/) and an API key to the sandbox and/or production environment - ## Installation -You can install the OpenApi IT Go Client with the following command using go get: - ```bash go get github.com/openapi-it/openapi-cli-go ``` - + ## Usage ```go -// main.go package main import ( + "bytes" + "context" + "encoding/json" + "log" + client "github.com/openapi-it/openapi-cli-go/pkg/client" ) func main() { - // Initialize the oauth client on the sandbox environment ctx := context.Background() + + // Initialize the OAuth client on the sandbox environment oauthClient := client.NewOauthClient("", "", true) // Create a token for a list of scopes scopes := []string{ - "GET:test.imprese.openapi.it/advance", - "POST:test.postontarget.com/fields/country", + "GET:test.imprese.openapi.it/advance", + "POST:test.postontarget.com/fields/country", } ttl := 3600 - resp, err := oauthClient.CreateToken(ctx, scopes, ttl) // returns the json as string + resp, err := oauthClient.CreateToken(ctx, scopes, ttl) if err != nil { log.Fatal(err) } - // The string response can be parsed into a custom object + // Parse the token response tokenResponse := struct { Scopes []string `json:"scopes"` Token string `json:"token"` }{} _ = json.Unmarshal([]byte(resp), &tokenResponse) - // Initialize the client - client := client.NewClient(tokenResponse.Token) + // Initialize the API client with the token + apiClient := client.NewClient(tokenResponse.Token) - // Make a request with params + // GET request with query params params := map[string]string{ "denominazione": "altravia", "provincia": "RM", "codice_ateco": "6201", } - _, err = client.Request( - ctx, - "GET", - "https://test.imprese.openapi.it", - "/advance", - nil, params, - ) + _, err = apiClient.Request(ctx, "GET", "https://test.imprese.openapi.it", "/advance", nil, params) if err != nil { log.Fatal(err) } - // Make a request with a payload + // POST request with a payload payload := struct { Limit int `json:"limit"` Query struct { CountryCode string `json:"country_code"` } `json:"query"` }{ - Limit: 0, + Limit: 10, Query: struct { CountryCode string `json:"country_code"` }{CountryCode: "IT"}, @@ -128,19 +116,12 @@ func main() { if err := json.NewEncoder(&buf).Encode(payload); err != nil { log.Fatal(err) } - _, err = client.Request( - ctx, - "POST", - "https://test.postontarget.com", - "/fields/country", - &buf, - nil, - ) + _, err = apiClient.Request(ctx, "POST", "https://test.postontarget.com", "/fields/country", &buf, nil) if err != nil { log.Fatal(err) } - // Delete the token + // Delete the token when done _, err = oauthClient.DeleteToken(ctx, tokenResponse.Token) if err != nil { log.Fatal(err) @@ -148,7 +129,6 @@ func main() { } ``` - ## Contributing Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. @@ -192,5 +172,4 @@ The MIT License is a permissive open-source license that allows you to freely us In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. -For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). - +For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). \ No newline at end of file diff --git a/examples/api_calls.go b/examples/api_calls.go deleted file mode 100644 index 75d7401..0000000 --- a/examples/api_calls.go +++ /dev/null @@ -1,29 +0,0 @@ -', '', true); - - $scopes = [ - 'GET:test.imprese.openapi.it/advance', - 'POST:test.postontarget.com/fields/country' - ]; - - $ttl = 3600; - $result = $oauthClient->createToken($scopes, $ttl); - - $tokenData = json_decode($result, true); - - if (isset($tokenData['token'])) { - echo "Generated token: " . $tokenData['token'] . PHP_EOL; - echo "Token created successfully!" . PHP_EOL; - } else { - echo "Error creating token: " . $result . PHP_EOL; - } - -} catch (Exception $e) { - echo "Error: " . $e->getMessage() . PHP_EOL; -} \ No newline at end of file diff --git a/examples/api_calls/api_calls.go b/examples/api_calls/api_calls.go new file mode 100644 index 0000000..f14e9b8 --- /dev/null +++ b/examples/api_calls/api_calls.go @@ -0,0 +1,51 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + + "github.com/openapi-it/openapi-cli-go/pkg/client" +) + +func main() { + ctx := context.Background() + + apiClient := client.NewClient("") + + // GET request with query parameters + params := map[string]string{ + "denominazione": "altravia", + "provincia": "RM", + "codice_ateco": "6201", + } + result, err := apiClient.Request(ctx, "GET", "https://test.imprese.openapi.it", "/advance", nil, params) + if err != nil { + log.Fatal(err) + } + fmt.Printf("GET API Response: %s\n", result) + + // POST request with payload + payload := struct { + Limit int `json:"limit"` + Query struct { + CountryCode string `json:"country_code"` + } `json:"query"` + }{ + Limit: 10, + Query: struct { + CountryCode string `json:"country_code"` + }{CountryCode: "IT"}, + } + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(payload); err != nil { + log.Fatal(err) + } + result, err = apiClient.Request(ctx, "POST", "https://test.postontarget.com", "/fields/country", &buf, nil) + if err != nil { + log.Fatal(err) + } + fmt.Printf("POST API Response: %s\n", result) +} \ No newline at end of file diff --git a/examples/token_generation.go b/examples/token_generation.go deleted file mode 100644 index 89a4a39..0000000 --- a/examples/token_generation.go +++ /dev/null @@ -1,34 +0,0 @@ -'; - $client = new Client($token); - - // GET request with parameters - $params = [ - 'denominazione' => 'altravia', - 'provincia' => 'RM', - 'codice_ateco' => '6201' - ]; - - $result = $client->get('https://test.imprese.openapi.it/advance', $params); - echo "GET API Response: " . $result . PHP_EOL; - - // POST request with payload - $payload = [ - 'limit' => 10, - 'query' => [ - 'country_code' => 'IT' - ] - ]; - - $result = $client->post('https://test.postontarget.com/fields/country', $payload); - echo "POST API Response: " . $result . PHP_EOL; - -} catch (Exception $e) { - echo "Error: " . $e->getMessage() . PHP_EOL; -} \ No newline at end of file diff --git a/examples/token_generation/token_generation.go b/examples/token_generation/token_generation.go new file mode 100644 index 0000000..a63a3ed --- /dev/null +++ b/examples/token_generation/token_generation.go @@ -0,0 +1,39 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + + "github.com/openapi-it/openapi-cli-go/pkg/client" +) + +func main() { + ctx := context.Background() + + // Initialize the OAuth client on the sandbox environment (test=true) + oauthClient := client.NewOauthClient("", "", true) + + scopes := []string{ + "GET:test.imprese.openapi.it/advance", + "POST:test.postontarget.com/fields/country", + } + ttl := 3600 + + resp, err := oauthClient.CreateToken(ctx, scopes, ttl) + if err != nil { + log.Fatal(err) + } + + tokenResponse := struct { + Scopes []string `json:"scopes"` + Token string `json:"token"` + }{} + if err := json.Unmarshal([]byte(resp), &tokenResponse); err != nil { + log.Fatal(err) + } + + fmt.Printf("Generated token: %s\n", tokenResponse.Token) + fmt.Println("Token created successfully!") +} \ No newline at end of file diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go new file mode 100644 index 0000000..3b134de --- /dev/null +++ b/pkg/client/client_test.go @@ -0,0 +1,55 @@ +package client + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestNewClient(t *testing.T) { + c := NewClient("test-token") + if c == nil { + t.Fatal("expected non-nil client") + } + if c.authHeader != "Bearer test-token" { + t.Errorf("expected auth header 'Bearer test-token', got %q", c.authHeader) + } +} + +func TestClientRequest(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bearer test-token" { + t.Errorf("wrong authorization header: %q", r.Header.Get("Authorization")) + } + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"status":"ok"}`)) + })) + defer server.Close() + + c := NewClient("test-token") + resp, err := c.Request(context.Background(), "GET", server.URL, "/test", nil, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "status") { + t.Errorf("unexpected response: %s", resp) + } +} + +func TestClientRequestWithParams(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Get("key") != "value" { + t.Errorf("expected query param key=value, got %v", r.URL.Query()) + } + w.Write([]byte(`{"ok":true}`)) + })) + defer server.Close() + + c := NewClient("token") + _, err := c.Request(context.Background(), "GET", server.URL, "/test", nil, map[string]string{"key": "value"}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } +} \ No newline at end of file diff --git a/pkg/client/oauthclient_test.go b/pkg/client/oauthclient_test.go new file mode 100644 index 0000000..18bf49a --- /dev/null +++ b/pkg/client/oauthclient_test.go @@ -0,0 +1,170 @@ +package client + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestNewOauthClient(t *testing.T) { + c := NewOauthClient("user", "apikey", false) + if c == nil { + t.Fatal("expected non-nil oauth client") + } + if c.baseURL != oauthBaseURL { + t.Errorf("expected base URL %q, got %q", oauthBaseURL, c.baseURL) + } + if !strings.HasPrefix(c.authHeader, "Basic ") { + t.Errorf("expected Basic auth header, got %q", c.authHeader) + } +} + +func TestNewOauthClientTest(t *testing.T) { + c := NewOauthClient("user", "apikey", true) + if c.baseURL != testOauthBaseURL { + t.Errorf("expected test base URL %q, got %q", testOauthBaseURL, c.baseURL) + } +} + +func TestGetScopes(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/scopes" { + t.Errorf("expected /scopes, got %q", r.URL.Path) + } + w.Write([]byte(`{"scopes":[]}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + resp, err := c.GetScopes(context.Background(), false) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "scopes") { + t.Errorf("unexpected response: %s", resp) + } +} + +func TestGetScopesWithLimit(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Get("limit") != "1" { + t.Errorf("expected limit=1, got %q", r.URL.Query().Get("limit")) + } + w.Write([]byte(`{"scopes":[]}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + _, err := c.GetScopes(context.Background(), true) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } +} + +func TestCreateToken(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + t.Errorf("expected POST, got %s", r.Method) + } + if r.URL.Path != "/token" { + t.Errorf("expected /token, got %q", r.URL.Path) + } + w.Write([]byte(`{"token":"abc123","scopes":["GET:test.example.com"]}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + resp, err := c.CreateToken(context.Background(), []string{"GET:test.example.com"}, 3600) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "token") { + t.Errorf("unexpected response: %s", resp) + } +} + +func TestGetTokens(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Get("scope") != "GET:test.example.com" { + t.Errorf("expected scope param, got %q", r.URL.Query().Get("scope")) + } + w.Write([]byte(`{"tokens":[]}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + resp, err := c.GetTokens(context.Background(), "GET:test.example.com") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "tokens") { + t.Errorf("unexpected response: %s", resp) + } +} + +func TestDeleteToken(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodDelete { + t.Errorf("expected DELETE, got %s", r.Method) + } + if !strings.HasSuffix(r.URL.Path, "/token-id") { + t.Errorf("expected path ending in /token-id, got %q", r.URL.Path) + } + w.Write([]byte(`{"deleted":true}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + resp, err := c.DeleteToken(context.Background(), "token-id") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "deleted") { + t.Errorf("unexpected response: %s", resp) + } +} + +func TestGetCounters(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/counters/daily/2024-01-01" { + t.Errorf("unexpected path: %q", r.URL.Path) + } + w.Write([]byte(`{"counters":[]}`)) + })) + defer server.Close() + + c := &OauthClient{ + baseURL: server.URL, + authHeader: "Basic dXNlcjpha2V5", + httpClient: &http.Client{}, + } + resp, err := c.GetCounters(context.Background(), "daily", "2024-01-01") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(resp, "counters") { + t.Errorf("unexpected response: %s", resp) + } +} \ No newline at end of file From d7804db666de8f95e9143bad8a4e56ca865feb02 Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 15:16:56 +0100 Subject: [PATCH 3/5] chore(makefile): update release target for official Go releases --- Makefile | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 3487268..7a188ae 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ ## ========= VERSION := 1.2.1 +TAG := v$(VERSION) ## ==================== ## Development Commands @@ -44,6 +45,9 @@ VERSION := 1.2.1 test: @go test ./... +vet: + @go vet ./... + dev-push: @git config credential.helper 'cache --timeout=3600' @git add . @@ -59,8 +63,24 @@ push: @git commit -am "Updated at $$(date)" || true @git push -release: push - @git add . - @git commit -m "Update Go SDK to version ${VERSION}" || echo "No changes to commit" - @git tag -fa "${VERSION}" -m "${VERSION}" - @git push origin --tags -f \ No newline at end of file +release: + @echo "==> Releasing $(TAG)..." + @if [ "$$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then \ + echo "ERROR: releases must be cut from the main branch"; exit 1; \ + fi + @if [ -n "$$(git status --porcelain)" ]; then \ + echo "ERROR: working directory is not clean"; exit 1; \ + fi + @echo "==> Running tests..." + @go test ./... + @echo "==> Running vet..." + @go vet ./... + @echo "==> Tagging $(TAG)..." + @git tag -a "$(TAG)" -m "Release $(TAG)" + @git push origin "$(TAG)" + @echo "==> Creating GitHub release..." + @gh release create "$(TAG)" \ + --title "$(TAG)" \ + --generate-notes \ + --verify-tag + @echo "==> Done. Release $(TAG) is live." \ No newline at end of file From 5e3cf8f9cf99b77203c408d371829ee7bb174d53 Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 15:18:00 +0100 Subject: [PATCH 4/5] Updated at mer 18 mar 2026, 15:18:00, CET --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7a188ae..9e2eb78 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ ## Variables ## ========= -VERSION := 1.2.1 +VERSION := 0.2.1 TAG := v$(VERSION) ## ==================== From 3d163836340adca23630346df95a7858b15a51c4 Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 15:23:06 +0100 Subject: [PATCH 5/5] fix(readme): update module path to openapi/openapi-go-sdk, split usage into two examples, add testing section --- README.md | 102 +++++++++++++----- examples/api_calls/api_calls.go | 2 +- examples/token_generation/token_generation.go | 2 +- go.mod | 2 +- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index cb65c43..4018ca8 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@

The perfect starting point to integrate Openapi® within your Go project

[![Build Status](https://github.com/openapi/openapi-go-sdk/actions/workflows/go.yml/badge.svg)](https://github.com/openapi/openapi-go-sdk/actions/workflows/go.yml) -[![Go Report Card](https://goreportcard.com/badge/github.com/openapi-it/openapi-cli-go)](https://goreportcard.com/report/github.com/openapi-it/openapi-cli-go) -[![Go Reference](https://pkg.go.dev/badge/github.com/openapi-it/openapi-cli-go.svg)](https://pkg.go.dev/github.com/openapi-it/openapi-cli-go) +[![Go Report Card](https://goreportcard.com/badge/github.com/openapi/openapi-go-sdk)](https://goreportcard.com/report/github.com/openapi/openapi-go-sdk) +[![Go Reference](https://pkg.go.dev/badge/github.com/openapi/openapi-go-sdk.svg)](https://pkg.go.dev/github.com/openapi/openapi-go-sdk) [![License](https://img.shields.io/github/license/openapi/openapi-go-sdk)](LICENSE)
[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members) @@ -44,63 +44,98 @@ For a complete list of all available services, check out the [Openapi Marketplac ## Installation +Add the SDK to your project: + ```bash -go get github.com/openapi-it/openapi-cli-go +go get github.com/openapi/openapi-go-sdk +``` + +Then import the client package: + +```go +import "github.com/openapi/openapi-go-sdk/pkg/client" ``` ## Usage +### Token generation + +Use `OauthClient` to authenticate with your credentials and generate a scoped access token. +The `test` flag switches between the sandbox (`true`) and production (`false`) OAuth endpoint. + ```go package main import ( - "bytes" "context" "encoding/json" + "fmt" "log" - client "github.com/openapi-it/openapi-cli-go/pkg/client" + "github.com/openapi/openapi-go-sdk/pkg/client" ) func main() { ctx := context.Background() - // Initialize the OAuth client on the sandbox environment oauthClient := client.NewOauthClient("", "", true) - // Create a token for a list of scopes scopes := []string{ "GET:test.imprese.openapi.it/advance", "POST:test.postontarget.com/fields/country", } - ttl := 3600 - resp, err := oauthClient.CreateToken(ctx, scopes, ttl) + resp, err := oauthClient.CreateToken(ctx, scopes, 3600) if err != nil { log.Fatal(err) } - // Parse the token response tokenResponse := struct { Scopes []string `json:"scopes"` Token string `json:"token"` }{} - _ = json.Unmarshal([]byte(resp), &tokenResponse) + if err := json.Unmarshal([]byte(resp), &tokenResponse); err != nil { + log.Fatal(err) + } + + fmt.Printf("token: %s\n", tokenResponse.Token) +} +``` + +### Making API calls + +Use `Client` with the token obtained above to call any Openapi service. +Pass the base URL and endpoint separately so the client can correctly attach query parameters. + +```go +package main - // Initialize the API client with the token - apiClient := client.NewClient(tokenResponse.Token) +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" - // GET request with query params + "github.com/openapi/openapi-go-sdk/pkg/client" +) + +func main() { + ctx := context.Background() + apiClient := client.NewClient("") + + // GET with query parameters params := map[string]string{ "denominazione": "altravia", "provincia": "RM", "codice_ateco": "6201", } - _, err = apiClient.Request(ctx, "GET", "https://test.imprese.openapi.it", "/advance", nil, params) + result, err := apiClient.Request(ctx, "GET", "https://test.imprese.openapi.it", "/advance", nil, params) if err != nil { log.Fatal(err) } + fmt.Println(result) - // POST request with a payload + // POST with a JSON payload payload := struct { Limit int `json:"limit"` Query struct { @@ -116,19 +151,38 @@ func main() { if err := json.NewEncoder(&buf).Encode(payload); err != nil { log.Fatal(err) } - _, err = apiClient.Request(ctx, "POST", "https://test.postontarget.com", "/fields/country", &buf, nil) - if err != nil { - log.Fatal(err) - } - - // Delete the token when done - _, err = oauthClient.DeleteToken(ctx, tokenResponse.Token) + result, err = apiClient.Request(ctx, "POST", "https://test.postontarget.com", "/fields/country", &buf, nil) if err != nil { log.Fatal(err) } + fmt.Println(result) } ``` +More complete examples are available in the [`examples/`](examples/) directory. + +## Testing + +The SDK ships with a suite of unit tests that use `net/http/httptest` — no real network calls, no credentials needed. + +Run the full suite: + +```bash +go test ./... +``` + +Run with verbose output to see each test case: + +```bash +go test -v ./pkg/client/... +``` + +Run a single test by name: + +```bash +go test -v -run TestCreateToken ./pkg/client/... +``` + ## Contributing Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. @@ -139,7 +193,7 @@ See [docs/contributing.md](docs/contributing.md) for detailed instructions on ho Meet the project authors: -- L. Paderi ([@lpaderiAltravia](https://www.github.com/lpaderiAltravia)) +- Michael Cuffaro ([@maiku1008](https://www.github.com/maiku1008)) - Openapi Team ([@openapi-it](https://github.com/openapi-it)) ## Partners diff --git a/examples/api_calls/api_calls.go b/examples/api_calls/api_calls.go index f14e9b8..e68ee3b 100644 --- a/examples/api_calls/api_calls.go +++ b/examples/api_calls/api_calls.go @@ -7,7 +7,7 @@ import ( "fmt" "log" - "github.com/openapi-it/openapi-cli-go/pkg/client" + "github.com/openapi/openapi-go-sdk/pkg/client" ) func main() { diff --git a/examples/token_generation/token_generation.go b/examples/token_generation/token_generation.go index a63a3ed..fc989a4 100644 --- a/examples/token_generation/token_generation.go +++ b/examples/token_generation/token_generation.go @@ -6,7 +6,7 @@ import ( "fmt" "log" - "github.com/openapi-it/openapi-cli-go/pkg/client" + "github.com/openapi/openapi-go-sdk/pkg/client" ) func main() { diff --git a/go.mod b/go.mod index a27ab13..7e126dd 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/openapi-it/openapi-cli-go +module github.com/openapi/openapi-go-sdk go 1.19