Il est possible d'accepter un dossier et d'y joindre le justificatif via les API GraphQL. Mais avant cela, voici un petit tour d'horizon du fonctionnement :
3 étapes :
1. Vous demandez a notre API une authorisation pour uploader un fichier sur notre object storage.
Cette requete implique de décrire le fichier que vous allez envoyer : le filename, byteSize, checksum (un digest md5, base64digesté) et son contenu. Ceci pour nous permettre de valider que nous echangeons le meme fichier, qu'il n'a pas été altéré etc.. Nous vous renvoyons :
les crédentials pour communiquer avec notre object storage
l'identifiant du fichier (blob_signed_id) a utiliser dans une autre requete pour le lier à une autre mutation
2. Vous uploadez le fichier sur notre object storage, en réutilisant les crédentials de la 1ere requete
3. Vous, client, faites une requete pour lier ce fichier (maintenant sur nos serveurs, identifié par le signed_blob_id) a un justificatif
1ere étape : demander les crédentials
Utiliser la mutation createDirectUpload. Voici un exemple complet de script que vous pouvez executer :
FILE=./file.txt \
FILE_TYPE="text/plain" \
API_TOKEN="VOTRE_TOKEN" \
DOSSIER_ID="un identifiant de dossier, cf: dossiers.id (ce n'est pas le numero de dossier)" \
ruby ./get_credentials.rb
get_credentials.rb
require 'net/http'
require 'uri'
require 'json'
require 'byebug'
require 'digest'
ENDPOINT = URI('https://www.demarches-simplifiees.fr/api/v2/graphql')
QUERY_UPLOAD_REQUEST = "
mutation createDirectUpload($input: CreateDirectUploadInput!) {
createDirectUpload(input: $input) {
directUpload {
url
headers
blobId
signedBlobId
}
}
}
"
### that's the HTTP part
# open an http connexion to our GraphQL endpoint
def open_http_connection
http = Net::HTTP.new(ENDPOINT.host, ENDPOINT.port)
if ENDPOINT.scheme == 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
http
end
# the headers of our http query, include auth
def request_headers
{
"Content-Type" => "application/json",
"Authorization" => "Bearer #{ENV.fetch('API_TOKEN') { raise 'missing env var API_TOKEN=xxx' }}"
}
end
def compute_checksum_in_chunks(io)
Digest::MD5.new.tap do |checksum|
while (chunk = io.read(5242880))
checksum << chunk
end
io.rewind
end.base64digest
end
def request_direct_upload_credentials(http, file)
data = {
"query" => QUERY_UPLOAD_REQUEST,
"operationName" => "createDirectUpload",
"variables" => {
"input" => {
"dossierId" => ENV.fetch("DOSSIER_ID") { raise "missing env var DOSSIER_ID=xxx" },
"filename" => file.path,
"byteSize" => file.size,
"checksum" => compute_checksum_in_chunks(file),
"contentType" => ENV.fetch("FILE_TYPE") { raise 'missing file type' }
}
}
}
pp "SENT DATA : #{data.inspect}"
req = Net::HTTP::Post.new(ENDPOINT, request_headers)
req.body = data.to_json
http.request(req)
end
fp = ENV.fetch('FILE') { raise 'missing env var FILE' }
File.open(fp, 'r') do |file|
http = open_http_connection
response = request_direct_upload_credentials(http, file)
body = JSON.parse(response.body)
puts body.inspect
credentials = body['data']['createDirectUpload']['directUpload']
credentials_headers = JSON.parse(credentials['headers'])
puts <<~CURL
curl -vvv \
--data-binary @#{file.path} \
-X PUT \
-H "Content-Type: #{credentials_headers['Content-Type']}" \
-H "ETag: #{credentials_headers['ETag']}" \
"#{credentials['url']}"
CURL
end
Aussi notre script echo un exemple pour uploader le fichier via curl, il vous suffit de le copier/coller pour envoyer le même fichier sur notre object storage
2eme étape : Uploader le fichier en utilisant les crédentials
curl -vvv --data-binary @./file.txt -X PUT -H "Content-Type: LE type de votre fichier" -H "ETag: LAVALEUR PRESENTE DANS LA REPONSE, au niveau de headers.etag [attention, c'est un json a parser]" "data[createDirectUpload][directUpload][url]"
3eme étape : Associer ce fichier lors de l'acceptation du dossier.
En préambule, il vous faut envoyer ce message au nom d'un instructeur, nous vous renvoyons à la documentation pour lister les id des instructeurs.
Utiliser la mutation dossierAccepter. Voici un exemple complet de script que vous pouvez executer :
SIGNED_BLOB_ID="Le signed blob id de la 1ere requete" API_TOKEN="votre token d'api" DOSSIER_ID="l'id de votre dossier" INSTRUCTEUR_ID="l'id de l'instructeur" ruby ./accept_with_pj.rb
accept_with_pj.rb
require 'net/http'
require 'uri'
require 'json'
ENDPOINT = URI('https://www.demarches-simplifiees.fr/api/v2/graphql')
QUERY = "
mutation dossierAccepter($input: DossierAccepterInput!) {
dossierAccepter(input: $input) {
dossier {
id
}
errors {
message
}
}
}
"
### that's the HTTP part
# open an http connexion to our GraphQL endpoint
def open_http_connection
http = Net::HTTP.new(ENDPOINT.host, ENDPOINT.port)
if ENDPOINT.scheme == 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
http
end
# the headers of our http query, include auth
def request_headers
{
"Content-Type" => "application/json",
"Authorization" => "Bearer #{ENV.fetch('API_TOKEN') { raise 'missing env var API_TOKEN=xxx' }}"
}
end
def accept_dossier_and_link_justificatif(http)
data = {
"query" => QUERY,
"operationName" => "dossierAccepter",
"variables" => {
"input" => {
"dossierId" => ENV.fetch('DOSSIER_ID') { raise 'missing env var DOSSIER_ID' },
"instructeurId" => ENV.fetch('INSTRUCTEUR_ID') { raise 'missing env var INSTRUCTEUR_ID' },
"justificatif" => ENV.fetch('SIGNED_BLOB_ID') { raise 'missing SIGNED_BLOB_ID env var' }
}
}
}
req = Net::HTTP::Post.new(ENDPOINT, request_headers)
req.body = data.to_json
response = http.request(req)
pp JSON.parse(response.body)
end
http = open_http_connection
puts accept_dossier_and_link_justificatif(http)